# Under what conditions must an instance refuse to mint a federated capability token when peer trust attestations are transitively satisfiable but locally unverifiable **Date of Record:** 2026 November 14 **Scope:** Applies to cross-organizational multi-agent federation where agents in one trust domain (the *minting domain*) issue capability tokens to agents in another (the *presenting domain*) based on a chain of peer attestations. Does not apply to single-org agent meshes, to pure OAuth2 client-credentials flows within one IdP, or to token exchange where the presenting agent's key material is directly pinned by the minting domain. ## Core Distinction The failure mode is the confusion between **transitive satisfiability** and **local verifiability** of a trust chain. A chain of attestations is *transitively satisfiable* when, following the graph of signed statements `A attests B`, `B attests C`, `C attests D`, there exists a path from the minting domain to the presenting agent's domain in which every edge carries a valid signature. A naive negotiator checks each edge's signature, sees "all good," and mints. A chain is *locally verifiable* only if the minting domain can, using only keys and revocation state it holds or can freshly fetch, evaluate every edge **at the moment of minting**, including: (a) whether each intermediate domain's attestation key was authorized *for the specific scope being delegated* (not just for signing), (b) whether each intermediate domain's own trust roots are within the minting domain's policy-anchored root set, and (c) whether revocation has been observed for each edge within the freshness window. The non-obvious boundary: **a chain can be fully signature-valid and still fail local verifiability**, because signature validity is a property of edges while verifiability is a property of the *anchoring* of the whole path to a root the minting domain already trusts. Multi-agent federation routinely produces chains where every hop is a legitimate, well-signed edge between two honest parties, yet the chain crosses a domain whose root is unknown to the minting domain — and the transitive check passes anyway. ## What Was Observed In a three-org federation (call them Alpha, Beta, Gamma), Alpha minted a capability token for an agent presenting a chain `Alpha → Beta → Gamma → agent`. Beta's attestation of Gamma was genuine and correctly signed with Beta's *general federation signing key*. The chain verified transitively. Alpha minted. The token granted `write:artifact` scope. Beta's attestation of Gamma, however, had been issued under Beta's *read-only federation policy* — Beta's signing key was authorized to attest peers, but the attestation carried a scope-restriction extension (a `delegation_scope` claim) that Beta's policy engine attached specifically to prevent downstream write delegation. The transitive verifier checked signatures and expiry but did not evaluate the `delegation_scope` claim against the requested scope, because that claim is a *semantic* constraint, not a cryptographic one. The signature was valid; the delegation was not authorized. Separately, Gamma's root certificate had been rotated 40 minutes prior and Beta had not yet propagated the new root. Alpha's transitive check found a valid signature on the `Beta → Gamma` edge (signed before rotation) but could not, at mint time, confirm that Gamma's *current* root was in Alpha's anchored set — because Alpha had never been given Gamma's root, only Beta's attestation of it. The path was satisfiable; it was not locally verifiable. Both conditions coexisted. The mint succeeded. The token was later used to write an artifact that Gamma's own policy would have rejected had Gamma been asked to authorize it directly — Gamma trusted the minting domain's token over its own local policy, which is the intended behavior and the reason the failure propagated silently. ## Condition of Validity The transitive check is a valid substitute for local verification **only when all three of the following hold**: 1. **Scope monotonicity holds along every edge.** Each attestation's `delegation_scope` is a superset of the scope requested at the leaf. This is a claim about the *content* of attestations, not their signatures, and must be evaluated explicitly. If any edge carries a scope restriction, transitive satisfiability does not imply delegation authority. 2. **The root set is closed under the path.** Every domain appearing on the path has its root present in the minting domain's policy-anchored root set *at mint time*, or is reachable from an anchored root via edges the minting domain can freshly re-verify. "Freshly" means within the revocation freshness window; a signature valid at issue time but unverifiable at mint time does not count. 3. **Revocation state is observable for every edge.** If the minting domain cannot query revocation status for an intermediate domain (e.g., Gamma's revocation endpoint is unreachable, or Beta's revocation list is stale beyond the window), the edge is *unverifiable*, not *valid-by-default*. When any condition fails, the correct action is to refuse to mint and to surface the specific unmet condition — not to fall back to the transitive result. ## Decision Boundary The boundary is sharp: **mint only if the path is locally verifiable; treat transitive satisfiability as necessary but not sufficient.** The operational rule: - If every edge is signature-valid AND scope-monotone AND root-anchored AND revocation-fresh → mint. - If every edge is signature-valid but *any* edge fails scope monotonicity, root anchoring, or revocation freshness → **refuse**, do not downgrade scope silently, and do not attempt to "complete" the chain by fetching missing roots from the peer itself (a peer cannot vouch for its own anchoring). - If the chain is incomplete (a missing edge) → refuse; do not attempt to synthesize the missing edge from reputation, prior sessions, or peer assertion. The subtle case that trips implementations: a chain where the *only* failing edge is the final hop from the presenting domain to the agent, and that hop is a self-attestation. Self-attestation is not a trust edge; it is a claim by the presenting domain about its own agent. It must be anchored by a prior, externally-issued attestation of the presenting domain, or it does not count. ## Operational Effect Refusing on transitive-but-unverifiable chains converts a silent authorization escalation into a visible negotiation failure. The observable effects: - **Latency increases on first contact** with a new intermediate domain, because the minting domain must fetch and anchor that domain's root before minting. This is correct; the alternative is unauthorized delegation. - **Federation graphs develop "hard edges"** — paths that cannot be traversed without out-of-band root exchange. Operators must treat root-set membership as a provisioning step, not a runtime discovery step. - **Scope restrictions become load-bearing.** Any attestation carrying a `delegation_scope` narrower than the full federation scope must be evaluated at every hop, because the transitive verifier will not catch it. - **Revocation freshness windows become a liveness constraint on federation.** A domain that cannot serve revocation state within the window is effectively unreachable for minting, which is the intended backpressure. The invariant to encode: *a federated capability token is only as trustworthy as the weakest edge the minting domain can independently verify at mint time; transitive signature validity is evidence of honesty, not of authority.* ```python from dataclasses import dataclass from typing import Optional class FederationMintRefused(RuntimeError): """Raised when a federated capability token cannot be minted because the trust path is transitively satisfiable but not locally verifiable.""" pass @dataclass class Edge: issuer: str subject: str signature_valid: bool delegation_scope: frozenset root_anchored: bool revocation_fresh: bool def mint_federated_token( path: list, requested_scope: frozenset, anchored_roots: frozenset, freshness_window_ok: bool, ) -> str: if not path: raise FederationMintRefused("empty trust path: nothing to verify") for i, edge in enumerate(path): if not edge.signature_valid: raise FederationMintRefused( f"edge {i} ({edge.issuer}->{edge.subject}) signature invalid" ) if not requested_scope.issubset(edge.delegation_scope): raise FederationMintRefused( f"edge {i} ({edge.issuer}->{edge.subject}) scope restriction " f"{sorted(edge.delegation_scope)} does not cover requested " f"{sorted(requested_scope)}; transitive signature validity " f"does not imply delegation authority" ) if not edge.root_anchored or edge.issuer not in anchored_roots: raise FederationMintRefused( f"edge {i} ({edge.issuer}->{edge.subject}) issuer root not in " f"anchored root set at mint time; path is satisfiable but not " f"locally verifiable" ) if not edge.revocation_fresh or not freshness_window_ok: raise FederationMintRefused( f"edge {i} ({edge.issuer}->{edge.subject}) revocation state " f"stale or unobservable; unverifiable edge is not valid-by-default" ) return f"token(scope={sorted(requested_scope)}, path_len={len(path)})" ```