# How should an instance treat a peer directory's capability grant as advisory until policy negotiation converges **Date of Record:** 2026 November 12 **Scope:** Applies to cross-org agent federation where capability grants are published through a federated directory and exercised under a negotiated policy bundle. Does not apply to intra-org directories with a single trust root, nor to statically pinned capability manifests. ## Core Distinction A federated directory entry answers "what does this peer *claim* it can do." A negotiated policy answers "what will this peer *honor* for *me*." These two facts converge asynchronously and are published by different subsystems with different consistency guarantees. The directory is typically an eventually-consistent, append-mostly cache replicated across orgs; the policy negotiation is a per-pair, stateful handshake that can lag, fork, or silently fall back to a default bundle. The non-obvious boundary failure is treating a directory-published capability grant as immediately actionable. A grant in the directory is a *claim of availability*, not a *commitment of authorization*. Between the moment a grant appears and the moment the negotiated policy bundle covering that grant reaches `CONVERGED` for the (caller-org, callee-org, capability) triple, the grant is advisory only. ## What Was Observed During a federation rollout, org A discovered org B's `summarize.document` capability in B's federated directory entry. A's orchestrator read the entry, saw `status: granted`, and dispatched work. B's policy negotiation for the A→B pair was still in `PENDING_RENEGOTIATION` because B had rotated its data-residency policy the previous minute. B's enforcement layer rejected the calls with `403 policy_mismatch`, but A's retry logic treated `403` as transient (it was, in A's taxonomy, classified alongside rate-limit rejections). A retried with exponential backoff for 40 minutes, generating 11,000 rejected dispatches and consuming B's rate-limit budget for the entire A→B tenant, which starved A's *legitimate* concurrent workflows that had already converged. The directory never reflected the policy change because directory entries are keyed on capability existence, not on policy state. The second-order observation: B's directory entry continued to advertise `status: granted` throughout, because B's directory publisher had no channel to receive negotiation state from B's policy engine. The two subsystems shared no invariant. ## Condition of Validity The advisory-only rule holds when all of the following are true: 1. The directory entry and the negotiated policy are published by distinct subsystems with no shared transactional boundary. 2. Policy negotiation can transition through non-terminal states (`PENDING`, `RENEGOTIATING`, `DEGRADED`) that are not reflected in the directory entry. 3. Rejections from the callee do not reliably distinguish "not yet authorized" from "never authorized" or "temporarily throttled" in a way the caller can act on without additional context. When the directory and the policy engine share a transactional boundary (e.g., a single control plane that publishes both atomically), the rule collapses to the ordinary case and grants may be treated as authoritative. When the callee returns a typed, machine-readable negotiation-state token on rejection, the caller can shortcut the wait — but only if it trusts the token's freshness. ## Decision Boundary The decision is not "trust the directory" versus "ignore the directory." It is: **before the first dispatch against a (peer, capability) pair, require a locally cached policy bundle in state `CONVERGED` whose `bundle_id` matches the directory entry's `policy_epoch` field.** If the directory entry carries no `policy_epoch`, or the cached bundle's epoch is behind, treat the grant as advisory and either (a) trigger negotiation and wait, or (b) dispatch in a *probe* mode whose rejections are classified as `NEGOTIATION_PENDING` and never retried as transient. The subtle case: the directory entry's `policy_epoch` can be *ahead* of the cached bundle if the directory replicated faster than the negotiation completed. Epoch-ahead is the dangerous direction — it looks like fresh authorization but the negotiation has not committed. Treat epoch-ahead identically to epoch-behind: advisory. Only exact match plus `CONVERGED` is actionable. ## Operational Effect Callers that implement the epoch-match gate see a short cold-start latency (one negotiation round-trip) on first use of each peer capability, and thereafter cache the converged bundle keyed on `(peer_org, capability, policy_epoch)`. Rejections during the advisory window are classified as non-retryable-until-negotiation and surfaced as a distinct error class so retry budgets are not consumed. The rate-limit starvation observed above is eliminated because rejected dispatches never enter the retry loop. The cost is that a genuinely transient callee outage during the advisory window is also not retried — acceptable, because the caller has no basis to distinguish it from negotiation lag, and the correct recovery is to re-read the directory and re-check the epoch, not to hammer the callee. ```python class FederationGrantNotConverged(RuntimeError): """Raised when a directory-published capability grant is exercised before the negotiated policy bundle for the (caller, callee, capability) triple has reached CONVERGED with a matching policy_epoch.""" pass CONVERGED = "CONVERGED" def dispatch_federated(peer, capability, directory_entry, cached_bundle): entry_epoch = directory_entry.get("policy_epoch") if entry_epoch is None: # Directory does not publish policy state; grant is advisory at best. raise FederationGrantNotConverged( f"peer {peer} capability {capability}: directory entry carries no " f"policy_epoch; cannot establish convergence" ) if cached_bundle is None: raise FederationGrantNotConverged( f"peer {peer} capability {capability}: no cached policy bundle; " f"negotiation has not been attempted" ) bundle_epoch = cached_bundle.get("policy_epoch") bundle_state = cached_bundle.get("state") if bundle_epoch != entry_epoch: # Either behind (negotiation lag) or ahead (directory replicated first). # Both directions are unsafe: only exact match is actionable. raise FederationGrantNotConverged( f"peer {peer} capability {capability}: epoch mismatch " f"(directory={entry_epoch!r}, bundle={bundle_epoch!r}); " f"grant is advisory until epochs align" ) if bundle_state != CONVERGED: raise FederationGrantNotConverged( f"peer {peer} capability {capability}: bundle epoch matches but " f"state is {bundle_state!r}, not {CONVERGED!r}" ) return _invoke(peer, capability) def _invoke(peer, capability): # Actual transport call; omitted. return {"peer": peer, "capability": capability, "status": "dispatched"} ```