Things we say cannot happen.
Each line below is a claim, and each names the test that holds it up. The list is generated from the suite rather than written by hand, and the generator's own test fails our build if this page stops matching what passes. Rename one of these tests and the build objects.
// Invariant: a caller // cannot escalate… func TestBodyActor…go/ast reads the annotationthe claim, in words TestBodyActor… · file:lineA page of guarantees maintained by hand becomes a page of former guarantees, and nothing tells you when it happened. This one is regenerated from the suite, and a build step compares the two, so the page cannot describe a guarantee the code stopped making.
Authority cannot be self-asserted
a Card's amounts are counted in its own currency only.
someone tries refund $300 on a USD payment against a Card limited to 50 EURwhat happens KIFF reads the payment's currency first; a call in another currency, or one it can't check, is refused and nothing is sentgateway TestACallInAnotherCurrencyIsNotSent apps/gateway/internal/gateway/unit_test.go:53once KIFF accepts a phone's signature for another service, that service saves the account's contract and permit targets with the phone's session, each once, within a minute, and nothing else (kiff/tafs#206).
someone tries a phone's session writes the contract with no grant, reuses a grant, uses it on another route, after it ended, or with another sessionwhat happens 403 without a live grant of this session, 409 for a second use, and no route but the two writeshandlers TestADeviceGrantAdmitsTheTwoWritesOnce apps/api/internal/handlers/device_signature_test.go:96the owner's halt binds in observe mode too. Observe makes KIFF's decisions advisory while an account watches what enforcing would do; a halt is the owner stopping an agent, not a decision to watch.
someone tries an agent of an account in observe mode keeps acting after the owner halts it, because the refusal comes back advisorywhat happens the halted refusal is labelled observe and is not advisoryhandlers TestAHaltBindsInObserveMode apps/api/internal/handlers/halt_refusal_test.go:85while the owner has halted an agent, or its whole account, KIFF decides none of its calls: a new call, a retry of one decided before and a held call asked again are all refused (halted), so nothing is sent and no permit is issued. Once resumed, only new calls go through: what was asked before the halt stays refused.
someone tries an agent keeps calling after the owner halts it, retries an operation allowed before the halt, or waits out the halt to collect a held call the owner had approvedwhat happens every decision for a halted agent or account is blocked with halted; after a resume, an operation first decided before the halt is blocked with halted toohandlers TestAHaltRefusesEveryCallAndNothingFromBeforeComesBack apps/api/internal/handlers/halt_refusal_test.go:23a hard refusal has nothing to approve. A call past a Card set to refuse is refused with no held call behind it, so the owner's list shows nothing to answer, and approving it by its call's id finds nothing.
someone tries a call past a Card set to refuse, then an approval of that refusal, by the call's id or by guessing a held call'swhat happens no held call is made, the owner's list is empty, and approve-once answers 404handlers TestAHardRefusalHasNothingToApprove apps/api/internal/handlers/gate_c_test.go:21a phone's approval key is replaced only when its own person approves the new key in their browser, after the new key proved itself.
someone tries code holding the phone's session and device key (no prompt) swaps in an approval key of its own, or another person approves the swapwhat happens the device key alone only asks; the new key must sign the request; only the session's person, in the browser, approves; nothing changes before thathandlers TestARelinkReplacesTheApprovalKeyOnlyWhenItsPersonApproves apps/api/internal/handlers/device_relink_test.go:148a person's run grant goes with each call KIFF decides, and a grant KIFF refuses sends nothing. The gateway never decides on the grant itself: only KIFF can say who it is for.
someone tries a run whose person may no longer use the agent, or with a forged grant, issues a refundwhat happens KIFF refuses the call on the grant and the tool receives nothinggateway TestARunGrantGoesWithEachDecision apps/gateway/internal/gateway/grant_test.go:11a trial (agent~trial) reads and halts as its agent, so planque, which asks KIFF about a trial permit's subject, refuses a trial's calls under its agent's halt, and after a resume a trial permit issued before it.
someone tries a trial permit issued just before the owner halts the agent is sent through planque within its lifetime, or after the resumewhat happens the trial's halt is its agent's, with the same halted_athandlers TestATrialReadsAsItsAgentsHalt apps/api/internal/handlers/halts_test.go:239a write whose vendor answer doesn't match what KIFF decided is flagged and its operation paused.
someone tries a vendor refunds 700 where the Card decided 500, or a read-back that can't be madewhat happens the call is recorded as sent and flagged; the operation is paused and nothing more is sent through it until the owner resumes itgateway TestAVerifyReadThatDiffersPausesTheOperation apps/gateway/internal/gateway/verify_test.go:45a write that doesn't carry its amount is limited by the amount its resource has, as KIFF reads it.
someone tries answer a 9,000 EUR dispute through a Card that holds anything over 1,000, by leaving the amount out or naming a small onewhat happens KIFF reads the dispute's amount itself and decides on it; an amount the agent sends is refused, and so is a call whose amount can't be readgateway TestAWriteIsLimitedByTheAmountItsResourceHas apps/gateway/internal/gateway/amount_test.go:46a revision draft changes an agent's Cards only when an owner confirms it, all of them or none, keeping each revised Card's usage so its totals don't start again, and it gives no key.
someone tries an agent drafts a revision of its own Card with a higher limit, hoping it applies before an owner confirms, resets the day's totals, or yields a second keywhat happens nothing changes until an owner confirms; then the Card is revised under the same id with what it used kept, and no claim secret or key comes out of ithandlers TestAgentDraftRevisesTheAgentsCards apps/api/internal/handlers/agent_drafts_revision_test.go:68a key bound to an agent cannot author a domain, export or delete the account, or choose what it is for, even when it holds the admin role.
someone tries use an admin key bound to an agent to rewrite the contract it is governed by, download every receipt, or delete the accountwhat happens these act for the account's people and require the owner's or an admin's session or a key not bound to an agenthandlers TestAgentKeyCannotActForTheAccount apps/api/internal/handlers/agent_key_account_test.go:18a key bound to an agent never holds the tenant_owner or admin role.
someone tries mint an agent's key with admin, or grant admin to it later, so domain permissions bound to admin reach the agentwhat happens minting or granting an account role onto an agent's key is refused, and a stored one resolves without itauth TestAgentKeyCannotHoldAccountRoles apps/api/internal/auth/agent_key_test.go:41an agent's own key cannot issue, share or answer for a Card, even when it holds the admin role.
someone tries mint an admin-role key bound to the agent, then issue itself a Card, add itself to another agent's Card, or approve its own held actionwhat happens managing Cards and answering for them require the owner's or an admin's own session or key, never one bound to an agenthandlers TestAgentKeyCannotManageCards apps/api/internal/handlers/shared_card_test.go:128a key bound to an agent cannot mint, grant or revoke keys, even when it holds the admin role.
someone tries mint an admin key bound to an agent, then use it to mint an unbound admin key and act as the account's ownerwhat happens key management requires the owner's or an admin's session or a key not bound to an agentauth TestAgentKeyCannotManageKeys apps/api/internal/auth/agent_key_test.go:16a key bound to an agent reads only the Cards that agent holds, alone or shared; another agent's Card is not listed and its statement is not found, even by its id (#1034). An agent's gateway key does not reach these routes at all.
someone tries agent A's key lists the account's Cards, or asks for agent B's Card statement by idwhat happens gateway keys stop at the gateway route list; other agent keys see only Cards their agent holdshandlers TestAgentKeyReadsOnlyCardsItsAgentHolds apps/api/internal/handlers/mandates_agent_isolation_test.go:112reading its Card gives an agent's key no way to change one.
someone tries an agent key that can read its Card tries to issue or revoke onewhat happens issuing and revoking stay gated on the management roleshandlers TestAgentKeyStillCannotIssueOrRevoke apps/api/internal/handlers/mandates_agent_card_test.go:239no key bound to an agent, and no runtime key, reads held work: not the list of card exceptions and not one by id, whoever's agent it belongs to or whichever Card it breached, shared or not. Held work carries the call's parameters and the Card's limits (#1036).
someone tries an agent's gateway or runtime key lists card exceptions, or reads another agent's held call by idwhat happens reading held work needs the account roles or a person's membership; keys bound to an agent never hold eitherhandlers TestAgentKeysCannotReadHeldWork apps/api/internal/handlers/mandate_exceptions_isolation_test.go:24no key bound to an agent, and no runtime key, watches the account's live decisions: it cannot subscribe to the event stream, so it never receives another agent's decision (#1036).
someone tries agent A's runtime or gateway key opens GET /v1/me/stream and waits for agent B's decisionswhat happens the stream is the account's view; it needs the account roles or a person's membershiphandlers TestAgentKeysCannotWatchTheDecisionStream apps/api/internal/handlers/stream_isolation_test.go:67through the real router, agent A's key reads only Cards agent A holds: not agent B's, by list or by id; a Card they share is visible to both. People and account keys read every Card (#1037, #1036).
someone tries agent A's runtime key lists Cards or reads agent B's Card statement by idwhat happens the Card list and statement are scoped to the key's agent; unbound runtime keys do not reach themmain TestAgentKeysSeeOnlyTheirOwnCardsThroughTheRouter apps/api/cmd/api/runtime_key_boundary_test.go:412a tool that checks KIFF's execution permit never receives an allowed call without one, and that call is reported as not sent.
someone tries get an allowed decision for a permit-checking tool with no permit attachedwhat happens the gateway does not forward it and records that it was never sentgateway TestAllowedWithoutPermitIsNotSent apps/gateway/internal/gateway/gateway_test.go:1052another KIFF service takes a person's act signed on their phone only when KIFF confirms that phone signed that exact request, once, and the person may connect tools (kiff/tafs#206: connecting the account's control server through the gateway).
someone tries a phone's session replays a signed request, changes its body, or asks without the right to connect tools; another key askswhat happens a replay is 409, another body or path is 403, a role without tools.connect is 403, and only a phone's session may askhandlers TestAnotherServiceAsksWhetherThePhoneSignedIt apps/api/internal/handlers/device_signature_test.go:31A caller cannot escalate its own authority by decorating the actor it submits. Authority is resolved from policy-owned membership keyed by actor id; the roles on the request body carry no authorization power.
someone tries Submit an approval request whose body carries actor.roles = ["admin"]what happens Roles are resolved from policy for that actor id. The roles in the payload are descriptive metadata with no authorization powerhandlers TestApprovalRequest_BodyActorCannotEscalate apps/api/internal/handlers/tenant_runtime_approvals_test.go:299an agent's own key cannot grant or deny an approval, even one it may review by role or by grant.
someone tries request an approval with an agent's key, then grant it with the same key, which holds the reviewer permissionwhat happens a key bound to an agent never reviews; a person on the account answers the approvalhandlers TestApprovalReview_AgentKeyCannotReview apps/api/internal/handlers/tenant_runtime_approvals_test.go:695a key cannot grant or deny an approval it asked for, even when it holds the reviewer permission.
someone tries ask for an approval with a key that may also review it, naming another actor as the requester, then grant it with the same keywhat happens the key that asked is recorded with the approval and refused its review; another reviewer answers ithandlers TestApprovalReview_KeyCannotReviewWhatItAskedFor apps/api/internal/handlers/tenant_runtime_approvals_test.go:736approve once authorizes exactly one action, the one the owner saw, and does not raise the Card. That action still counts in full toward the Card's totals.
someone tries after the owner approves one €1,500 refund once, reuse the approval for a different amount, or send the same proposal again hoping for a second authorizationwhat happens the approval binds to the request's fingerprint and is consumed once; an identical retry replays the same authorization, a changed one is refused, and the full amount is drawn from the Cardmandate TestApproveOnce apps/api/internal/mandate/exception_test.go:174the agent's Card read answers only a key bound to an agent; a person or an unbound key has no agent whose Card it could show.
someone tries call GET /v1/me/card with a key that is not bound to an agentwhat happens the handler requires the identity's agenthandlers TestCardReadNeedsAnAgentKey apps/api/internal/handlers/mandates_agent_card_test.go:226a subject cannot exceed its cumulative limit, however many individually-permitted actions it proposes. Per-action ceilings bound one mistake; this bounds the day.
someone tries propose a further €600 refund after €4,600 has already been refunded today, each one individually under the per-action ceilingwhat happens the draw is added to the window's running total before the decision, so the 51st compliant action is refused when the 50 before it exhausted the limitmandate TestCumulativeLimitRefusesTheActionThatCrossesIt apps/api/internal/mandate/mandate_test.go:52a call made under a trial its owner started is decided on the trial's Cards alone, drawing on them, and recorded under the trial; a call without it never sees them. Once the trial ends, its calls, held ones included, are refused.
someone tries an agent names a trial to get the version's higher limit for its live calls, names another agent's trial, or keeps a held trial call to be approved after the trial endedwhat happens only the key of the trial's own agent can name it; live calls get the live Card; after the end, the trial's calls are refused with trial_endedhandlers TestDecideATrialsCallOnItsTrialCards apps/api/internal/handlers/proposals_trial_test.go:123an API key cannot approve a device sign-in, so an agent's key cannot turn itself into an owner session.
someone tries start a CLI sign-in, approve it with an agent's gateway key, and use the developer session it mints, which acts as the account's ownerwhat happens approving a device sign-in requires a signed-in person; an API key gets 403 and no session is mintedhandlers TestDeviceAuth_APIKeyCannotApprove apps/api/internal/handlers/device_auth_test.go:330A caller cannot grant itself a permission by putting a role on the actor in the request body. The execute gate resolves roles from policy, never from the payload.
someone tries POST an action with actor.roles = ["approver"] in the request bodywhat happens The execute gate reads roles from policy, never from the payload, and refusesmain TestExecuteGate_BodyRolesCannotEscalate apps/api/cmd/api/execute_role_gate_test.go:160An API key past its expiry authenticates nowhere: every route the API registers answers 401 to it, an account key's and an agent's alike, as it does to a revoked key.
someone tries A leaked key that was meant to stop working keeps reading or acting after its expiry datewhat happens authentication checks the key's expires_at against the clock before any route or handler runsmain TestExpiredKeysAuthenticateNowhere apps/api/cmd/api/runtime_key_boundary_test.go:353an expired or revoked mandate never widens authority. It is reported as expired rather than falling through to "no mandate applies", which would turn an expiry into a grant.
someone tries let a mandate lapse, then propose the action it used to bound, hoping the check finds no active mandate and waves it throughwhat happens a lapsed mandate that covers the action is reported as expired, so the decide path refuses instead of treating the subject as unboundedmandate TestExpiredMandateDoesNotFallThroughToUnbounded apps/api/internal/mandate/mandate_test.go:125an external approver's answer cannot go past its grant. Over its per-call ceiling, outside its Card, past a total, after its grant is withdrawn or expires, after the Card changes, or for its own call, the answer is refused and the hold stays as it was.
someone tries have a connected approver service answer a held call outside what its grant coverswhat happens the answer is refused; the call stays held with its deadline unchanged, and nothing is drawnmandate TestExternalApproverBoundaries apps/api/internal/mandate/external_approver_test.go:66a tool cannot speak for KIFF: it cannot write the dev.kiff/ result metadata that clients rely on.
someone tries have a tool return _meta["dev.kiff/call"] claiming its call was approvedwhat happens the tool's dev.kiff/ keys are removed from forwarded results, the first time and on replay, and the gateway writes its own call state; the tool's other metadata passes throughgateway TestForwardedResultCannotSpeakForKIFF apps/gateway/internal/gateway/gateway_test.go:921a gateway key is always bound to an agent. Neither creating a key nor adding a role to one yields a gateway_agent key without an agent.
someone tries mint a gateway_agent key with no agent_id, or add gateway_agent to an unbound keywhat happens key creation and role grants require an agent binding for gateway_agentauth TestGatewayKeyMustBeBoundToAnAgent apps/api/internal/auth/agent_key_test.go:174a trial's writes through the gateway get the decisions the same queue of real calls would get from the agent's Cards, each counting the trial's earlier allowed writes, and KIFF records nothing real for them: no draw, no held call, nothing for the owner to answer.
someone tries an agent key sends trial calls inside and outside its Card, to use up the Card's total or fill the owner's queue without ever calling the toolwhat happens each trial call is answered allowed, held or refused as the same real queue would be, and the Card's draws and held calls stay emptyhandlers TestGatewayTrialDecidesAndRecordsNothing apps/api/internal/handlers/gateway_trial_test.go:128Work held for a Card's owner is refused once its hold expires unanswered, and stays refused.
someone tries let a €1,500 refund held for the owner sit past its hold expiry, then retry it and have the owner approve it latewhat happens every retry is refused as owner_expired, the late approval is refused, and nothing is drawnmandate TestHeldWorkExpires apps/api/internal/mandate/hold_expiry_test.go:19A runtime key cannot manage keys. Credentials issued for calling the decision API cannot mint, rotate, or revoke other credentials.
someone tries Use a runtime key, the credential agents call the decision API with, to mint a second keywhat happens Key management requires a management identity. The runtime key is refusedauth TestKeysHandler_RuntimeKeyCannotManage apps/api/internal/auth/keys_handler_test.go:447a lifetime total never resets. Calls across days draw on one total, so a daily-looking budget cannot be spent once per day.
someone tries spend the Card's total, wait for midnight (or 24 hours), spend it againwhat happens the next day's call is refused while the lifetime total is spentmandate TestLifetimeTotalNeverResets apps/api/internal/mandate/lifetime_test.go:25reissuing a Card cannot reset its lifetime total, not by moving ValidFrom later and not by switching a daily total to a lifetime one: every draw the Card has made counts.
someone tries spend most of the room, then reissue the Card with a later ValidFrom (or a new window) to get it backwhat happens the reissued Card still counts the earlier drawsmandate TestLifetimeTotalSurvivesReissue apps/api/internal/mandate/lifetime_test.go:59a sign-in token issued through one connect link works only at that link's URL.
someone tries use a token issued through a connect link at the general gateway URLwhat happens the general URL refuses itgateway TestLinkURLAcceptsOnlyItsOwnTokens apps/gateway/internal/gateway/oauth_internal_test.go:105a mandate that sums a parameter an action does not declare as numeric is refused when it is issued, not discovered at runtime.
someone tries issue a mandate capping sum(reason), where reason is a string, so the limit silently sums nothing and never bindswhat happens issue-time validation reads the action's declared parameter types and rejects the mandatemandate TestMandateSummingANonNumericParameterIsRefusedAtIssue apps/api/internal/mandate/mandate_test.go:263only Setup's key reads another agent's Card through kiff_card; a taf's key that names another agent is refused, and reads nothing.
someone tries call kiff_card with agent set to another agent, from a taf's gateway keywhat happens cardResult requires the setup_reader role before naming an agentgateway TestOnlySetupNamesAnAgentInKiffCard apps/gateway/internal/gateway/card_test.go:205only Setup's key reads another agent's Card; a taf's own key sees only the Cards it holds, whatever agent it names.
someone tries call GET /v1/me/card?agent=<another agent> with a gateway agent's keywhat happens the handler requires the setup_reader role to name an agenthandlers TestOnlySetupReadsAnotherAgentsCard apps/api/internal/handlers/mandates_agent_card_test.go:210an action outside a Card set to come home is held for the Card's owner and authorizes nothing until the owner answers.
someone tries propose a €1,500 refund against a Card allowing €500 each whose work comes home, and retry it until it goes throughwhat happens it is held as one owner exception and every retry returns owner_required with the same handle; nothing is drawnmandate TestOutsideTheCardComesHome apps/api/internal/mandate/exception_test.go:85an agent's gateway key pasted into a client reaches the same routes as an OAuth token for that agent, and only the two its own runtime needs besides (a person's access to that agent, and resolving their run grant): not the account's Cards, held work, event stream, agents or export.
someone tries use an agent's pasted gateway key to read the rest of the account through GET /v1/me/* routeswhat happens the middleware applies the gateway route list to any agent-bound gateway_agent key, not only to OAuth tokensauth TestPastedGatewayKeyReachesOnlyGatewayRoutes apps/api/internal/auth/oauth_test.go:91reading the list of pending calls decides, draws and sends nothing, and an agent's key sees only its own calls.
someone tries read kiff_pending with another agent's key, or read it repeatedly hoping it sends the held callwhat happens the other key sees nothing, and reading never forwards; only the original call collects it, oncegateway TestPendingListsAHeldCallUntilItIsCollected apps/gateway/internal/gateway/pending_test.go:57one action cannot carry more than the per-action limit, however much the Card's total has left.
someone tries propose a single €1,500 refund against a Card allowing €500 each and €5,000 a day, with nothing spent yetwhat happens the per-action limit is checked before the totals and refuses with its own outcomemandate TestPerActionLimit apps/api/internal/mandate/per_action_test.go:40revocation cannot be undone by re-issuing the same mandate id. Authority that was withdrawn stays withdrawn until a new mandate is issued under a new id.
someone tries revoke a mandate, then POST the original definition again with the same id to restore itwhat happens revoked_at is never read from a request body and is excluded from the issue upsert, so a re-issue leaves the revocation standinghandlers TestReIssuingDoesNotUnrevoke apps/api/internal/handlers/mandates_test.go:123A read-only account key (role viewer, bound to no agent) reads the account's activity, held work and stream, and changes nothing: every write route the API registers, including ones added later, refuses it before any handler, and so do reads that need more than reading (the export, the audit log). The same role on an agent's key leaves it that agent's runtime key.
someone tries A key minted to read the account writes through it (answers a hold, mints a key, changes a Card, halts, approves a device sign-in, leaves the account)what happens The route policy lets a read-only key make only GET and HEAD requests that need the read capability; it holds no other capabilitymain TestReadOnlyAccountKeyOnlyReads apps/api/cmd/api/runtime_key_boundary_test.go:254a refusal's next step is one the held call's own Card offers, and it stays a refusal: nothing is drawn, the call ends, and the agent can read what the owner asked it to do instead.
someone tries refuse with a next step the Card does not list, or treat a refusal with a next step as permission to actwhat happens an unlisted step is rejected with ErrNextStepNotOnCard and the hold stays open; a listed one records the refusal, draws nothing and the call stays refusedmandate TestRejectWithNextStep apps/api/internal/mandate/next_step_test.go:28every spelling of kiff_card is the gateway's own tool. A tool connected under one before the name was reserved is neither listed nor reached.
someone tries call a connected tool named KIFF_Card that tools/list hideswhat happens CallTool answers every reserved spelling as kiff_card before any invocation is begungateway TestReservedSpellingNeverReachesAConnectedTool apps/gateway/internal/gateway/card_test.go:228a call on a resource outside the Card comes home to its owner, and an approval covers that exact resource only.
someone tries get inv-9 approved once, then redeem the same proposal id for inv-8, or a new proposal for inv-9what happens the approval binds to the resource in the request fingerprint; a new proposal is held againmandate TestResourceOutsideComesHomeAndApprovalBindsTheResource apps/api/internal/mandate/resource_scope_test.go:104a Card scoped to named resources authorizes the action only on those resources.
someone tries an agent holding a refund Card for invoice inv-1 refunds inv-9, or sends no invoice at allwhat happens the call is outside the Card (resource_not_on_card), checked before amounts, never read as "not covered"mandate TestResourceScope apps/api/internal/mandate/resource_scope_test.go:43an unscoped Card covering the same action never widens a scoped one. Cards are conjunctive, so the scope binds.
someone tries hold a scoped Card for inv-1 and a broad refund Card, and refund inv-9what happens the scoped Card is breached whichever order the Cards are read inmandate TestResourceScopeStacksWithUnscopedCard apps/api/internal/mandate/resource_scope_test.go:82a runtime credential cannot issue or revoke a mandate. A key that could grant itself authority would make every limit advisory.
someone tries use the agent's own decide credential to POST a mandate granting itself a larger limitwhat happens issuing is gated on the management roles, the same separation that stops a runtime key minting sibling keyshandlers TestRuntimeKeyCannotIssueItsOwnMandate apps/api/internal/handlers/mandates_test.go:65a runtime key (an agent's key, or any key without the account roles) cannot read the account's activity, settings or people's things, nor change them: the decision stream, evidence, receipts, proof packs, usage, alert targets, billing budget, notification preferences, support tickets, the key list (#1036).
someone tries an agent's runtime key reads account-wide activity or changes account settings through GET/PUT/POST /v1/me/* routes that only check the tenantwhat happens the route policy lets a runtime key reach only RuntimeKeyRules; every other route, including ones added later, is refusedmain TestRuntimeKeysReachOnlyRuntimeRoutes apps/api/cmd/api/runtime_key_boundary_test.go:134Setup's key acts on the account's own control server only on a Card of its own (Coach's), and still never on a vendor's tool that writes.
someone tries Setup calls the control server's tool with no Card, or a vendor's write once the control server is connectedwhat happens no Card of Setup's own is refused as not issued; the vendor's write is refused for the rolehandlers TestSetupActsOnTheControlServerOnlyOnItsCard apps/api/internal/handlers/setup_reads_decide_test.go:140Setup's Card for its reads is issued only on the owner's approval of that connection, which KIFF checks itself (the device's signature over planque's approve request, a person who may connect tools, signed within a day), only by the connector key that connected the tools, and only for tools marked read-only. It allows a few reads a day and refuses past them.
someone tries planque's connector key, or anyone holding one, grants an agent authority the owner never approved: another connection's or another account's approval, an old one, another person's device, a tool that writes, or a tool another key connectedwhat happens each is a 403 and no Card is issuedhandlers TestSetupReadsCardNeedsTheOwnersApproval apps/api/internal/handlers/setup_reads_test.go:78Setup's key (setup_reader) reads a read-only tool only on its own read Card, and can't call a tool that writes, whatever Card names it.
someone tries Setup, which holds no tools, calls a tool that writes, or reads without the owner's approval of its readswhat happens a write is refused for the role; a read with no Card of Setup's own is refused as not issuedhandlers TestSetupReadsOnlyWhatItsCardAllows apps/api/internal/handlers/setup_reads_decide_test.go:58where several mandates cover one action, the tightest binds. Issuing an additional mandate can only narrow authority.
someone tries hold a generous domain-wide mandate and issue a second, narrower one, expecting the generous one to still permit the actionwhat happens mandates are conjunctive, so every covering mandate must have room and the tighter limit decidesmandate TestTighterMandateBindsWhenSeveralCover apps/api/internal/mandate/mandate_test.go:169a trial its owner started sends its calls (kiff/tafs#173). With KIFF-Trial naming a draft KIFF says is being tried, a call goes the normal path: recorded, decided with the draft named (so KIFF decides it on the trial's own Cards), sent when allowed, held when not, and its result names the draft. KIFF-Trial-Run isn't needed, and is harmless.
someone tries a version being tried issues one refund inside its trial Card and one outside itwhat happens the one outside is held for the owner and not sent; both are decided with the trial's draft, never as the live version's callsgateway TestTrialBeingTriedIsSentOnItsDraft apps/gateway/internal/gateway/trial_test.go:202a version being tried is decided on its own trial Cards, and the live version on the agent's Cards, each with its own counters. Trying it changes nothing on the live Cards, and no call made for the agent sees a trial Card.
someone tries start a trial of a version with a higher limit, then make the agent's ordinary calls, hoping they get the trial's limit, or the trial's spending counts against (or resets) the live Cardwhat happens the agent's calls are decided on its live Card as before; the trial's calls only on the trial Cards, from zero, until they lapse in 30 dayshandlers TestTrialCardsAreTheVersionsAndApartFromTheLive apps/api/internal/handlers/trial_cards_test.go:75a trial of an agent's next version is decided against the Cards as a real queue would be, its own earlier allowed writes counting toward the limits, and draws nothing real, holds nothing and asks no owner.
someone tries run a trial's refunds over and over, inside and outside the Card, to use up its total or fill the owner's queuewhat happens each trial write gets the decision the same queue of real calls would get, and the Card's total and the owner's queue are unchangedmandate TestTrialDecidesAndRecordsNothing apps/api/internal/mandate/trial_test.go:27a trial ends for good: going back, its runtime's sweep, or a new trial revoke its Cards, and only the agent's own key or someone who manages Cards can end it.
someone tries keep a trial's higher limits after going back, start a second trial to hold two sets of trial Cards, or end another agent's trial with this agent's keywhat happens one trial per agent; an ended trial's Cards are revoked; another agent's key is told there is no such drafthandlers TestTrialEndsAndRevokesItsCards apps/api/internal/handlers/trial_cards_test.go:155installing a version being tried issues its Cards live and revokes its trial Cards, together, and the trial records that it was installed.
someone tries install a tried version and keep its trial Cards in force beside the live ones, doubling its roomwhat happens the trial Cards are revoked in the same issue as the live revisionhandlers TestTrialInstallEndsIt apps/api/internal/handlers/trial_cards_test.go:243a trial's call is never sent, reads included. A call made with KIFF-Trial is decided against the agent's Cards and answered with that decision; it creates no invocation, records no request, draws nothing and never reaches the tool.
someone tries run a trial of a new version that issues refunds inside and outside its Card through the gatewaywhat happens each refund comes back with KIFF's decision (allowed, held) and "Nothing was sent"; the tool receives no call and nothing is recorded or drawngateway TestTrialWriteIsDecidedAndNeverSent apps/gateway/internal/gateway/trial_test.go:71an approval not yet used stops authorizing when its Card is revoked, moved to another holder, or expires.
someone tries have the owner approve an action once, then revoke or move the card, and redeem the approval anywaywhat happens revocation and moves invalidate open exceptions under the card's lock, and redemption rechecks the card under the same lockmandate TestUnusedApprovalIsWithdrawn apps/api/internal/mandate/exception_test.go:287a held or refused call never reaches the tool. A call is forwarded only on an allowed decision: inside the Card, or an approved per-action exception that still fits the Card's totals.
someone tries ask the gateway for a €5,000 refund on a Card that allows €500 per callwhat happens the €5,000 call is held with the owner's review link and not sent; the tool receives only the €500 call, and only €500 is drawngateway TestWithinCardForwardsOutsideHolds apps/gateway/internal/gateway/gateway_test.go:491
One tenant cannot reach another
an account's drafts are its own. Another account's person can't read, confirm or discard one by its id.
someone tries an owner of another account reads, confirms or discards a draft by its idwhat happens each answers 404, and the draft is unchangedhandlers TestAnotherAccountCantReachADraft apps/api/internal/handlers/gate_c_test.go:62one account cannot see, test, remove or decrypt another account's tool connections.
someone tries copy another account's encrypted tool credential into your own connectionwhat happens its seal is bound to the account it was made for, so it does not open; the other account's connection stays invisibleconnection TestConnectionsAreIsolatedByAccount apps/gateway/internal/connection/connection_test.go:328One tenant's API keys are never visible to another. Key listing is scoped at the storage boundary, not filtered after the fact.
someone tries Authenticate as tenant A and list API keys, hoping tenant B's appearwhat happens Listing is scoped at the storage boundary, so tenant B's keys are never in the result to be filtered outauth TestKeysHandler_Tenants_Are_Isolated apps/api/internal/auth/keys_handler_test.go:245Two tenants recording byte-identical facts commit to different Merkle leaves. A public anchor cannot be used as a confirmation oracle for a guessed record without also guessing that tenant's salt.
someone tries Guess a record, hash it, and look for that leaf in the public anchor to confirm the guesswhat happens Each tenant's leaves are salted with a per-tenant secret, so the guess produces a different hash and confirms nothinganchor TestLeafHashDifferentSaltsCrossTenantIsolation apps/api/internal/anchor/merkle_salt_test.go:54a literal copy of a tool's credential in its result is removed before the result is stored, returned to the agent or replayed.
someone tries connect a tool that echoes its bearer credential verbatim in a successful resultwhat happens the credential is replaced with [redacted] before the result is stored, so neither the response nor a replay carries itgateway TestSuccessfulResultIsRedacted apps/gateway/internal/gateway/gateway_test.go:891a connected tool cannot point KIFF at internal, loopback, link-local or cloud metadata addresses.
someone tries connect a tool whose URL resolves to localhost or the cloud metadata addresswhat happens the connection is refused before anything is contactedconnection TestUntrustedURLsAreRefused apps/gateway/internal/connection/connection_test.go:417
The record cannot quietly disagree with what happened
A receipt altered after signing fails verification against the anchored root. Tamper-evidence is checked, not asserted.
someone tries Change a field in a signed receipt and present it as genuinewhat happens The digest is recomputed from the receipt's own content, so the signature no longer recovers the declared signerreceipt TestAnchorAttester_TamperedReceiptFailsOnchainVerify apps/api/internal/receipt/anchor_attester_test.go:143A trace containing more than one execution is refused rather than turned into a receipt. A receipt describes exactly one executed action or it is not issued.
someone tries Feed the receipt builder a trace containing two executed actionswhat happens The build is refused. A receipt describes exactly one executed action or it is not issuedreceipt TestBuild_RejectsTraceWithMultipleExecutions apps/api/internal/receipt/build_test.go:313The bytes a receipt's signature commits to are pinned to a fixed encoding. Reordering a field would otherwise change every future hash while leaving past receipts verifiable, which is indistinguishable from tampering.
someone tries Reorder a field in the chain struct, changing what every future receipt hashes towhat happens The encoding is pinned to fixed bytes, so the build fails before a single receipt is signed against the new shapereceipt TestCausalChainCanonicalEncodingIsPinned apps/api/internal/receipt/canonical_test.go:39
What the gate never saw is reported, not assumed absent
A tool that ran more often than the gate was consulted is reported as undecided calls. Bypass is measured against recorded decisions rather than assumed absent.
someone tries Call a governed tool directly, bypassing the gate, and assume nobody can tellwhat happens Observed call counts are compared against recorded decisions, and the difference is reported as undecided callshandlers TestCoverage_ReportsCallsThatNeverReachedTheGate apps/api/internal/handlers/coverage_test.go:185
What happens when something breaks
a call already sent, or whose outcome is unknown, keeps its recorded outcome and key when the same operation comes again and its amount can't be read now.
someone tries make the vendor's read fail between a call and its retry, so the retry reads as never sent and the agent does it again under a new idwhat happens the retry answers with the recorded outcome and key; a held call stays held, never decided without its amountgateway TestARetryKeepsItsOutcomeWhenTheAmountCantBeReadNow apps/gateway/internal/gateway/amount_test.go:109an approved call is sent to the tool once, however many retries race to collect it.
someone tries after Approve once, send ten identical retries of the held call at the same timewhat happens exactly one claims the call; the tool receives it oncegateway TestApprovedHoldForwardsOnceUnderConcurrentRetries apps/gateway/internal/gateway/gateway_test.go:548When a source behind the evidence object is unavailable, that section is marked unavailable and the rest still answers. Evidence degrades section by section rather than failing whole or, worse, reporting an empty section as a clean one.
someone tries One source behind the evidence object is unavailable when a report is composedwhat happens That section is marked unavailable and the rest still answers, rather than an empty section reading as a clean oneevidence TestCompose_PostureReadError_Degrades apps/api/internal/evidence/composer_test.go:390a call whose delivery is in doubt is reported as unknown and is never sent again by KIFF.
someone tries kill the gateway after it claims a call for sending, then retry the callwhat happens after the lease the call reads unknown, and the retry does not reach the toolgateway TestCrashWhileForwardingIsUnknownAndNotResent apps/gateway/internal/gateway/gateway_test.go:785When two first sign-ins for the same subject race, exactly one tenant survives and the loser cleans up the one it provisioned. No orphan tenant is left behind.
someone tries Two first sign-ins for the same subject arrive at once, each provisioning a tenantwhat happens Exactly one survives and the loser deletes the tenant it created, leaving no orphantenant TestEnsureForSubject_LoserOfRaceCleansUpItsTenant apps/api/internal/tenant/ensure_test.go:270When the usage limiter cannot establish its own state, the request is allowed. Blocking a customer's production traffic because our meter was uncertain is the worse failure, and this default is deliberately the opposite of the governance one.
someone tries The usage limiter cannot reach its own store while a customer is mid-requestwhat happens The request is allowed. Blocking production traffic because our meter was uncertain is the worse failureusage TestLimiter_FlushFailureIsAllowedWhenUncertain apps/api/internal/usage/limiter_test.go:321when current usage cannot be established, the proposal is refused. A mandate is the authority itself, not a meter, so allowing when uncertain means acting with authority nobody could confirm.
someone tries make the draw ledger unreadable at the moment a proposal arrives, hoping the check degrades to allowwhat happens Evaluate returns ErrUsageUnavailable and the caller must refuse, the opposite default to the billing limiter beside it, which allows when uncertain on purposemandate TestMandateFailsClosedUnlikeTheUsageLimiter apps/api/internal/mandate/mandate_test.go:107If the audit write fails, the mutation does not happen. A suspended tenant with no audit record is not an outcome this system can produce.
someone tries Suspend a tenant at the moment the audit write failswhat happens The mutation rolls back. A suspended tenant with no audit record is not a state this system can reachhandlers TestOps_Suspend_AuditFailureLeavesTenantUnchanged apps/api/internal/handlers/ops_audit_failure_test.go:55planque confirms a halt by reading it back with its connector key, and that read never asks planque to confirm again, so one halt is one confirm, not a loop.
someone tries a halt whose confirm re-enters itself, so the ack is never recorded and every dispatch read starts the same stormwhat happens planque's read only answers; the halt is confirmed once and reads haltedhandlers TestPlanquesReadBackConfirmsOnceWithoutLooping apps/api/internal/handlers/halts_test.go:209if KIFF cannot record that a call was requested, the call is neither decided nor sent. A call with no record never reaches a tool.
someone tries make the request record fail while an agent's call arriveswhat happens the gateway fails closed: the tool is not called and nothing is drawngateway TestUnrecordedCallIsNotSent apps/gateway/internal/gateway/gateway_test.go:468
abuse
only the account's connector key says a vendor signed a connection out, and each sign-out alerts once an hour at most.
someone tries an agent's key or a person's session sends sign-out alerts for another taf, or a flapping vendor floods the owner's phonewhat happens anything but a connector key gets 403; a second alert for the same grant within the hour is droppedhandlers TestConnectionSignedOutAlertsOnceFromTheConnectorKey apps/api/internal/handlers/connection_signed_out_test.go:20
Authority is counted once, and never past a total
an approve-once waives a Card's total only when it is a count of 0 the owner reviewed on that hold ("Each call asks you first"), and only for that call: the call counts as used, and the next one asks again. A non-zero total, or any money total, is never waived by approving once.
someone tries approve one call on a Card that asks about each call, then send more calls hoping the approval carries them; or approve once past a 1-a-day count or a money totalwhat happens the next call is held again; a non-zero count or a money total gets can_approve_once false, and an approve-once of it waits as approved_no_roommandate TestApproveOnceWaivesOnlyACountOfZero apps/api/internal/mandate/exception_test.go:436reading the Card is not a governed call. It is answered by the gateway: nothing is recorded, decided, drawn or sent to a tool.
someone tries call kiff_card and expect it to count against a limit or reach a connected toolwhat happens CallTool answers kiff_card before any invocation is begungateway TestCardToolReadsWithoutDeciding apps/gateway/internal/gateway/card_test.go:79an approval cannot carry an action past a Card's total. If the total has no room when the approved action is retried, it waits and nothing is authorized.
someone tries approve one refund over the per-action limit, spend the Card's total down, then retry the approved refundwhat happens the retry is answered approved_no_room: the approval is kept, nothing is drawn or authorizedmandate TestNewCumulativeBreachAfterApprovalWaitsForRoom apps/api/internal/mandate/exception_test.go:338no bonus without its audit entry. If the entry can't be written, the bonus is taken back.
someone tries grant bonus tasks while the operator audit log is failingwhat happens grantBonus revokes the pack when the audit write failshandlers TestOps_BonusTasks_AuditFailureTakesTheBonusBack apps/api/internal/handlers/ops_bonus_test.go:92
privacy
sharing a taf lets someone use it, not read the account (RFC 050 decision 12). A person reads every call and hold of the tafs they manage, their own runs' calls, and, when they may answer holds, the holds of the tafs they use; an admin, or a person on an account from before roles, reads all of it.
someone tries a viewer a taf is shared with reads the account's Record, or another person's held call by idwhat happens KIFF scopes the Record and held calls to the reader; another person's hold reads as missinghandlers TestEachPersonReadsTheirOwnUse apps/api/internal/handlers/own_use_test.go:156
What this page is not.
The file and line are an index, not evidence. This repository is private, so you cannot open any of them, and a citation you cannot check is not proof of anything. What it is good for is picking: name a line and we open that file in front of you on a call and run it. That is a worse claim than a badge and a more useful one.
These cover apps/api, apps/gateway only, not every repository we publish, and they are the guarantees we chose to state, a passing test proves the property it tests and nothing else. Nothing here claims the set is complete, and a system with no failing tests is not a system with no flaws. We know that unusually well: three of four attacks against our own approval boundary worked, and the conformance tests passed the entire time it was broken, because they tested the compile-time property rather than the security one. Several of the tests above exist because of that.
These are also what we write against your claims when we put an action on rails: the attacks stay in your build, failing if the guarantee regresses. Showing you ours first is the point.