Guarantees & evidence
A protocol that sells auditability should be auditable. This table maps every guarantee we make to the function that enforces it and the published test that proves it.
npm pack @aroha-sdk/credentials, @aroha-sdk/delegation, @aroha-sdk/mcp-guard — then read src/). Anchors are file + function, not line numbers, so they survive refactors. Server-side guarantees cite the public spec instead of private code — we mark the difference rather than blur it.Authority can only narrow
A delegated spending limit can never exceed its parent's
Enforced at
@aroha-sdk/credentials · mandate.ts · assertNarrowing()
Proven by
mandate.test.ts · "rejects spendLimitUsd widening" (and the cart variant)
A delegated task scope is a strict subset of the parent's
Enforced at
@aroha-sdk/credentials · mandate.ts · assertTaskNarrowing()
Proven by
chain.test.ts · "rejects a scope widened mid-chain"
A blocked capability stays blocked all the way down a chain
Enforced at
@aroha-sdk/delegation · chain.ts · verifyMandateChain()
Proven by
chain.test.ts · "rejects a dropped blocked capability"
N children cannot multiply a parent budget (no double-allocation)
Enforced at
@aroha-sdk/credentials · spending-ledger.ts · SpendingLedger.allocate() → BudgetExhaustedError
Proven by
mandate.test.ts · "rejects allocation that would exceed parent limit"
Tokens cannot be forged, replayed, or redirected
Tampering with any field breaks the token
Enforced at
@aroha-sdk/credentials · mandate.ts · verifyMandate() / verifyTaskMandate() — Ed25519 over canonicalised JSON
Proven by
chain.test.ts · "rejects a tampered token"
A mandate is bound to exactly one grantee
Enforced at
@aroha-sdk/credentials · mandate.ts · verifyTaskMandate(expectedGrantee)
Proven by
mandate.test.ts · "rejects grantee mismatch"
Mandates expire; a stale grant is a dead grant
Enforced at
@aroha-sdk/credentials · mandate.ts · expiry check in both verifiers; chain-level containment in verifyMandateChain()
Proven by
mandate.test.ts and chain.test.ts · "rejects an expired mandate"
A rotated-out key cannot sign, and rotation cannot be replayed
Enforced at
Registry (server-side): nonce consumed atomically, 5-minute freshness window, self-signed by the outgoing key — see the public DID method spec, Update operation
Proven by
Specified in aroha-spec · spec/did-method.md · §Update; conformance test-matrix
Chains of custody cannot be spliced
Each link's grantor must be the previous link's grantee, with parentMandateId continuity
Enforced at
@aroha-sdk/delegation · chain.ts · verifyMandateChain()
Proven by
chain.test.ts · "rejects broken grantor→grantee custody"
A hop cannot be impersonated — every link's signature is checked against its signer's resolved key
Enforced at
@aroha-sdk/delegation · chain.ts · verifyMandateChain() + resolvePublicKey
Proven by
chain.test.ts · "rejects a child signed by the wrong key (impersonated hop)"
An untrusted root issuer is rejected at the door
Enforced at
@aroha-sdk/delegation · serve-delegated.ts · verifyRequest() — trust-anchor pinning
Proven by
examples/delegation-web/demo.mjs · scenario 3 (forged root → HTTP 400)
Recursion has a floor
maxDelegationDepth strictly decrements; a depth-0 mandate is a dead end
Enforced at
@aroha-sdk/delegation · chain.ts (chain rule) + serve-delegated.ts · delegate() (refuses before signing)
Proven by
chain.test.ts · "rejects any child under maxDelegationDepth=0", "rejects a child that fails to decrement depth", "rejects a child that omits depth when the parent bounds it"
The tool plane fails closed
Block beats limit beats gate — precedence is fixed, and a zero limit denies immediately
Enforced at
@aroha-sdk/mcp-guard · engine.ts · GuardEngine.decide()
Proven by
engine.test.ts · "applies precedence block > limit > gate", "a zero limit denies immediately"
An unanswered or unsupported approval prompt is a denial, never an allowance
Enforced at
@aroha-sdk/mcp-guard · proxy.ts · requestApproval() (timeout → settle(false)) and resolveGate() (client error → resolve(false))
Proven by
Deny paths implemented as the only defaults in proxy.ts; rule engine covered by the 17-test engine suite
Run the proofs yourself
The delegation demo exercises the chain guarantees live — three agents on localhost, including a forged root, a widened scope, and a blown depth limit, all rejected:
npm i @aroha-sdk/delegation @aroha-sdk/credentials @noble/ed25519 node examples/delegation-web/demo.mjs # ships in the delegation package docs