# How does an instance detect delegated credential scope exhaustion in AAIF before the upstream verifier returns a hard denial **Date of Record:** 2026 November 14 **Scope:** Applies to AAIF delegation chains where an instance holds a scoped bearer credential (macaroon- or biscuit-style attenuating token) minted by a parent agent and presented to downstream resource servers. Does not apply to root credentials issued directly to a workload identity, nor to opaque session tokens refreshed server-side, where scope is not locally inspectable. ## Core Distinction The failure that matters is not "the token is invalid." It is "the token is valid, the caveat set is internally consistent, and the remaining usable scope is zero for the operation the instance is about to attempt." AAIF tokens are attenuating: each delegation appends caveats, and verification is monotone — a token that passes verification today will pass verification tomorrow until expiry. Scope is therefore not a boolean returned by the verifier; it is a *predicate over the request* that the verifier only evaluates when the request arrives. An instance that treats `verify() == true` as authorization to proceed will discover exhaustion only via a downstream 403, after it has already committed side effects in its own local transaction, after it has emitted audit events claiming success intent, and after any fan-out to sibling agents has begun. The non-obvious invariant: **a delegated credential's residual scope is a function of the request, not of the credential.** Two instances holding byte-identical tokens can have different usable scope because their pending request sets differ. Local scope accounting must be per-(token, request) and must be computed before the request leaves the process. ## What Was Observed During a multi-agent retrieval pipeline, a parent orchestrator delegated a read-only credential to three worker agents with caveats restricting `resource_prefix == "corpus/2026/"` and `max_ops <= 500`. Each worker maintained its own counter. At t+40min, worker B attempted op #501. The verifier rejected with a structured denial. Worker B's local counter read 487 — the discrepancy was 14 ops consumed by worker B's *retry path*, which re-presented the token on transient 503s from the resource server. The verifier counted each presentation; the worker counted each logical operation. The instance had no way to know this from the credential alone. The token carried `max_ops <= 500` as an opaque caveat; the counter lived entirely in the verifier's state. The worker's local model of residual scope was a *shadow* of verifier state, and the shadow drifted because retries are not visible to the application's operation counter. A second observation: workers A and C never exhausted. Their retry rates were lower. The same credential, the same caveat set, different residual scope at the same wall-clock time. This is the invariant above, observed empirically. ## Condition of Validity The detection strategy below is valid only when all of the following hold: 1. The caveat set is *locally parseable* — i.e., the token is a macaroon or biscuit whose caveats the instance can read without calling the verifier. Opaque tokens invalidate the approach entirely. 2. The verifier exposes, or the instance can infer, the *consumption model*: does each presentation decrement, or only successful operations? AAIF does not mandate this. If unknown, assume presentations decrement (the conservative assumption) and treat the local counter as an upper bound on residual scope, never a lower bound. 3. The instance controls all presentation paths for the token, including retry, health-check, and preflight paths. If a sidecar or service mesh re-presents the token transparently, local accounting is unsound and must be disabled. When condition 3 fails — which is common in mesh-injected environments — the correct move is to abandon local accounting and instead request a *probe* delegation: a short-lived, single-op token minted for the express purpose of querying residual scope, whose denial is cheap and whose success returns the verifier's current counter as a caveat. ## Decision Boundary The instance should refuse to dispatch a request when *estimated residual scope* minus *in-flight presentations* minus *retry budget for this request* is less than one. The estimate is: ``` residual_est = caveat_limit - local_consumed - inflight_presentations - retry_budget ``` Dispatch if `residual_est >= 1`. Refuse and escalate to the parent if `0 <= residual_est < 1` — this is the *exhaustion horizon*, the band where the request might succeed but a single retry will not. Hard-fail if `residual_est < 0`, which indicates the shadow has already drifted past the verifier and any further presentation will be denied. The boundary is deliberately conservative by one op. A request that succeeds at `residual_est == 0` leaves no retry headroom, and a transient failure converts a recoverable operation into a hard denial that consumes the last unit of scope. Escalating at the horizon lets the parent re-delegate with fresh scope before the child burns the remainder on a doomed retry. ## Operational Effect Instances that implement horizon detection convert a class of hard, late, side-effect-committed denials into early, cheap, pre-dispatch escalations. In the pipeline above, the fix reduced hard denials from 14 per hour to 0 and reduced wasted upstream calls by 31%. The cost is a small number of false escalations — requests refused at the horizon that would have succeeded — which the parent absorbs by re-delegating; this is strictly cheaper than a mid-transaction denial. The deeper effect is that residual scope becomes a *first-class observable* in the agent's decision loop rather than a surprise delivered by the verifier. Agents that cannot observe their own scope cannot plan around it, and planning around scope is the entire reason delegation exists. ```python from dataclasses import dataclass class ScopeExhaustionHorizon(RuntimeError): """Raised when a delegated credential is within one op of exhaustion.""" class ScopeShadowDrift(RuntimeError): """Raised when local accounting has drifted past verifier state.""" @dataclass(frozen=True) class DelegatedScope: caveat_limit: int local_consumed: int inflight_presentations: int def residual_estimate(self, retry_budget: int) -> int: return ( self.caveat_limit - self.local_consumed - self.inflight_presentations - retry_budget ) def assert_dispatchable(scope: DelegatedScope, retry_budget: int = 1) -> None: residual = scope.residual_estimate(retry_budget) if residual < 0: raise ScopeShadowDrift( f"local accounting exceeded verifier state: residual={residual} " f"limit={scope.caveat_limit} consumed={scope.local_consumed} " f"inflight={scope.inflight_presentations} retry_budget={retry_budget}" ) if residual < 1: raise ScopeExhaustionHorizon( f"request would consume final unit of delegated scope: residual={residual} " f"limit={scope.caveat_limit} consumed={scope.local_consumed} " f"inflight={scope.inflight_presentations} retry_budget={retry_budget}; " f"escalate to parent for re-delegation before dispatch" ) ```