# Delegation How one identity lends its voice to another, and how a verifier decides whether a claim made by someone it does not know is backed by someone it does. The wire object is `DelegationClaim` (PROTOCOL.md §8.7, tag `0x07`). This document is about what it means and how chains are resolved. --- ## 1. The statement ``` granter says: grantee may issue claims covering these exact predicates, re-delegating at most max_depth further times. ``` - **Exact predicates only.** `{minecraft.op: true}` covers the key `minecraft.op` and nothing else. There are no prefixes and no wildcards: a grant of `user.` that silently covered `users.admin` would turn an administrative convenience into an escalation primitive. - **Every predicate value is the boolean `true`**, enforced at decode time. Coverage is membership, not interpretation (INV-5). - **`max_depth` counts hops below the grant.** `0` means the grantee speaks for itself only; `2` allows the grantee to delegate onward once, and that sub-grantee once more. - **Revocation mirrors claims**: the granter signs a `Revocation` targeting the delegation's object ID. Expired grants die on their own; supersession (`serial`) replaces terms without revoking history. ## 2. Chain resolution A consumer anchors trust in roots — issuers it already decided to believe (`Policy.TrustedIssuers`). When a claim's issuer is not a root, the verifier searches for a path: ``` trusted root ──grant──▶ … ──grant──▶ claim issuer ──claim──▶ subject ``` Rules, implemented deterministically in `verify.Graph`: 1. Every link must be signature-valid, current at the evaluation instant, unrevoked by its granter, and cover the claim's exact predicate. 2. Where several grants could serve, the highest `serial` wins, ties broken by lowest content ID — map order never leaks into a decision. 3. Total hops are bounded by `Policy.MaxDepth` (default 3), and each link's own `max_depth` must fit the hops below it: link *i* of *k* needs `max_depth ≥ k−1−i`. 4. Cycles cannot loop: depth bounds terminate every walk. 5. The accepted result reports the full path in `Result.Chain` (`issuer → … → root`) as audit evidence. An empty `TrustedIssuers` keeps the original model exactly: any issuer the consumer fed into the graph may satisfy the policy directly. Delegation only activates when roots are named. ## 3. What delegation does not mean - It is not identity merging: the claim still names its real issuer, and the chain names everyone who lent authority. - It is not transitive by default: a root that grants with `max_depth: 0` creates exactly one hop and nothing more. - A hostile link can stop forwarding, but cannot forge: every hop is signed by its own granter, and the root sees only grants it signed itself.