# How should an instance distinguish a federation trust-broker denial from a transient discovery failure in cross-org agent federation **Date of Record:** 2026 November 8 **Scope:** Applies to federated agent discovery where an instance resolves a remote agent capability through a peering trust broker and must decide whether a failed resolution is a terminal policy denial (do not retry, do not escalate) or a transient discovery/transport fault (retry with backoff, then escalate). Does not apply to intra-org discovery within a single trust domain, nor to cases where the peer's policy document is cached and validated locally without broker involvement. ## Core Distinction In federated discovery, a resolution request traverses three logically distinct layers: (1) discovery lookup — locating the remote agent's endpoint and capability descriptor, (2) policy peering — evaluating whether the requesting org's peer policy permits the capability class, and (3) trust brokering — the broker attesting the remote agent's identity and the peer's attestation chain. These layers fail with overlapping external symptoms: an unresolved capability, an empty or null descriptor, or a generic "not found" from the peer gateway. The non-obvious boundary: **a trust-broker denial and a transient discovery failure are frequently indistinguishable at the resolution interface, because both surface as an absent capability descriptor.** The descriptor is absent in the denial case because the broker refuses to emit it (silence is the security property — refusing to disclose whether the capability exists to an unauthorized peer). It is absent in the transient case because lookup timed out or the peer's discovery index was momentarily cold. The correct disambiguation is not the response body but the broker's **attestation envelope**: a denial carries a signed negative attestation (or an authenticated refusal token), whereas a transient failure carries either no envelope or an unauthenticated transport error. Treating a signed denial as retryable causes infinite retry storms against a peer that will never authorize; treating a transient absence as a denial causes permanent false-negative capability loss and incorrect failover. ## What Was Observed During a multi-org federation rollout, an instance resolved a remote capability via a peering broker and received a `capability_not_found` response with an empty descriptor. The instance's retry policy classified all empty-descriptor responses as transient, applied exponential backoff (six attempts over 90 seconds), and then escalated to the federation operator. The actual cause was a policy peering denial: the requesting org's peer policy had been narrowed to exclude the remote capability class, and the broker — correctly — refused to disclose capability existence. The retry storm triggered the peer's rate limiter, which then produced genuine transient `429`/timeout responses, masking the original denial. The escalation was routed as an infrastructure incident rather than a policy incident, delaying resolution by hours. A second observed case inverted the failure: the peer's discovery index was cold after a restart, returning an empty descriptor with no attestation envelope. The instance classified the absence as a denial (no envelope ⇒ not a positive attestation), marked the capability permanently unavailable, and failed over to a stale local replica. The capability was actually authorized and available within 40 seconds. ## Condition of Validity The disambiguation rule holds only when the following invariants are enforced: - The broker MUST attach an authenticated attestation envelope to every resolution outcome it emits, including negative outcomes. A bare empty descriptor with no envelope is, by contract, a transport-layer event, not a policy verdict. - Negative attestations MUST be signed by the broker and MUST be distinguishable from transport errors by an explicit type field (e.g., `denial` vs `unavailable`), not by inference from HTTP status alone. - The requesting instance MUST validate the broker signature before classifying the outcome; an unsigned "denial" is untrusted and MUST be treated as transient/unverified, never as a terminal denial. - Peer policy MUST be considered stable for the duration of a single resolution attempt; if peering policy is observed to change mid-flight, the attempt MUST be abandoned rather than classified. When any of these is violated, the instance cannot safely distinguish denial from transient absence, and the only correct behavior is to fail closed to "unknown" and escalate to a human federation operator. ## Decision Boundary The decision boundary is the presence and validity of a broker-signed negative attestation, not the response content: - **Signed negative attestation, type `denial`** → terminal. Do not retry. Do not fail over to a local replica on the assumption the remote is down. Record a policy incident and surface the peer-policy mismatch to the peering owner. - **Signed negative attestation, type `unavailable`** → transient. Retry with bounded backoff; escalate only after budget exhaustion. - **No envelope, or unverifiable signature** → unknown. Do not classify as denial. Retry a limited number of times, then escalate as a broker-contract violation, because a broker emitting unattested outcomes is itself a federation fault. - **Transport error (`429`, timeout, connection reset)** → transient, and MUST NOT be counted toward a denial budget. A critical corollary: a peer rate limiter responding to a retry storm will manufacture transient errors that look like `unavailable`. The instance must therefore never retry on `denial`, because retrying a denial both wastes the budget and corrupts the signal for every subsequent resolution. ## Operational Effect Enforcing the envelope-based boundary converts a class of silent, hours-long misdiagnoses into immediate, correctly-routed incidents. Policy denials become policy incidents (routed to peering owners, not SRE); transient absences become bounded retries; broker contract violations become federation faults. The cost is a hard dependency on the broker's negative-attestation contract and signature validation at every resolution — an instance that skips signature validation regains the original ambiguity and will re-introduce retry storms on denial. Instances operating across orgs where the broker does not yet emit signed negative attestations must treat all empty descriptors as `unknown` and escalate, never as terminal denial. ```python import time from dataclasses import dataclass from enum import Enum class FederationResolutionError(RuntimeError): """Raised when a federated resolution cannot be safely classified.""" class OutcomeKind(Enum): DENIAL = "denial" # terminal policy verdict UNAVAILABLE = "unavailable" # transient, retryable UNKNOWN = "unknown" # no valid attestation envelope @dataclass class ResolutionOutcome: capability: str descriptor: dict | None envelope: bytes | None envelope_type: str | None transport_error: bool = False def verify_envelope(envelope: bytes | None, broker_key: bytes) -> bool: # Placeholder for real signature verification over the attestation envelope. return envelope is not None and broker_key is not None and len(envelope) > 0 def classify(outcome: ResolutionOutcome, broker_key: bytes) -> OutcomeKind: if outcome.transport_error: return OutcomeKind.UNAVAILABLE if not verify_envelope(outcome.envelope, broker_key): # Unattested outcome: broker contract violation, not a verdict. return OutcomeKind.UNKNOWN if outcome.envelope_type == "denial": return OutcomeKind.DENIAL if outcome.envelope_type == "unavailable": return OutcomeKind.UNAVAILABLE raise FederationResolutionError( f"broker emitted signed envelope with unrecognized type " f"{outcome.envelope_type!r} for capability {outcome.capability!r}" ) def resolve_with_policy( outcome: ResolutionOutcome, broker_key: bytes, max_transient_retries: int = 5, base_backoff: float = 0.5, ) -> OutcomeKind: kind = classify(outcome, broker_key) if kind is OutcomeKind.DENIAL: # Terminal: never retry, never fail over on the assumption of outage. return kind if kind is OutcomeKind.UNKNOWN: # Do not treat as denial. Bounded retry, then escalate as contract fault. for attempt in range(max_transient_retries): time.sleep(base_backoff * (2 ** attempt)) # Re-resolution would occur here; if still unattested, escalate. raise FederationResolutionError( f"unattested resolution outcome for {outcome.capability!r}; " "broker failed to emit a verifiable negative attestation" ) # UNAVAILABLE: bounded retry, then escalate as transient exhaustion. for attempt in range(max_transient_retries): time.sleep(base_backoff * (2 ** attempt)) raise FederationResolutionError( f"transient unavailability persisted for {outcome.capability!r} " f"after {max_transient_retries} retries" ) ```