# When must an instance refuse a delegated capability token that is structurally valid but temporally incoherent across federation boundaries **Date of Record:** 2026 November 13 **Scope:** Applies to cross-org multi-agent federations where capability tokens (signed, attenuated, policy-scoped grants) are minted by an issuer org and delegated transitively through intermediate agents to a consuming instance in a different trust domain. Does not apply to single-org delegation, nor to tokens whose entire validity window is contained within one issuer's clock authority. ## Core Distinction The non-obvious boundary is between **structural validity** and **temporal coherence**. A capability token can pass every cryptographic and schema check — correct signature chain, correct attenuation (scope is a subset of the parent grant), correct audience binding, correct policy reference — and still be unusable, because the *time* under which each hop in the delegation chain asserts the token is live is evaluated against a different clock authority. Federation does not share a clock. Each org's policy engine stamps `not_before` / `not_after` and a `policy_evaluation_time` using its own monotonic-plus-wall-clock composite, and each org's revocation feed lags by its own replication interval. The failure mode is that an instance accepts a token whose *issuer-side* validity window has closed but whose *consumer-side* window (recomputed from a cached policy snapshot) still appears open. The token is not forged. The delegation is not unauthorized. It is simply **temporally incoherent**: the grant was valid at the moment of minting, and the consumer believes it is valid now, but no single instant exists at which both the issuer's revocation state and the consumer's policy snapshot agree the grant was live. This is a distributed-systems version of the "no consistent cut" problem, localized to capability lifetimes. ## What Was Observed In a three-org federation (A issues, B intermediates, C consumes), agent `C/worker-7` received a delegated `write:dataset` capability originally minted by `A/policy`. The chain was `A → B → C`, with attenuation at B narrowing scope from `write:*` to `write:dataset`. All signatures verified. The attenuation proof checked out. C's local policy snapshot (replicated from A every 90 seconds) showed the grant live for another 40 seconds. However, A had revoked the parent grant 12 seconds earlier due to a policy amendment, and B's revocation feed (replicated from A every 30 seconds) had not yet observed the revocation, so B continued to countersign downstream delegations. C accepted the token and executed a dataset write that A's policy had, at that instant, forbidden. The write was not a security breach in the classic sense — no attacker, no forged signature. It was a **coherence gap**: the intersection of (A's revocation-observed interval) ∩ (B's countersign-valid interval) ∩ (C's snapshot-valid interval) was empty, yet each pairwise intersection was non-empty. The token was valid under every local view and invalid under the global one. The tell was in the audit log: A's revocation timestamp was *earlier* than B's countersign timestamp, which was *earlier* than C's acceptance timestamp, but A's revocation had propagated to C's snapshot *after* C's acceptance. The ordering `revoke < countersign < accept` in wall-clock terms is impossible under correct delegation semantics; it only appears because the three clocks are not comparable. ## Condition of Validity A delegated capability token is safe to honor at consumer `C` **iff** there exists an instant `t` such that: 1. `t` is within the issuer's `[not_before, not_after]` window as evaluated by the issuer's clock; 2. `t` is within every intermediate's countersign window as evaluated by that intermediate's clock; 3. `t` is within C's accepted window as evaluated by C's clock; 4. `t` is *after* the issuer's revocation-feed watermark has been observed by C (i.e., C's snapshot is causally newer than any revocation event with timestamp ≤ `t`); 5. and the maximum clock skew across the chain, `max_i(skew_i)`, is strictly less than the minimum remaining validity margin `min_i(not_after_i - t)`. Condition 4 is the one instances routinely violate. It requires that C's policy snapshot be *causally* newer than the revocation feed, not merely *temporally* newer in wall-clock terms. A snapshot that was replicated 90 seconds ago cannot prove the absence of a revocation issued 12 seconds ago, no matter what its own timestamp says. Condition 5 is the quantitative guard: if any hop's clock can be off by more than the smallest remaining validity margin, the token must be treated as expired, because there exists a real instant at which one hop believes it is live and another believes it is dead. ## Decision Boundary The instance must **refuse** the token — raising a hard error, not a retryable one — when any of the following hold: - The consumer's revocation watermark is older than the token's `not_before` plus the maximum observed replication lag for the issuer's feed. (The consumer cannot prove the grant was un-revoked at minting time.) - Any hop's `policy_evaluation_time` precedes the previous hop's `countersign_time` by more than the configured skew budget. (The chain asserts an ordering that clocks cannot support.) - The minimum remaining validity margin across all hops is less than the federation's declared `max_clock_skew`. (The token is within the skew shadow.) - The attenuation proof at any hop was evaluated against a policy snapshot whose causal version is older than the parent grant's issuance version. (The attenuation was computed against a stale view of the parent's scope.) The instance must **not** refuse merely because wall-clock timestamps appear out of order across orgs; that is expected under skew and is not itself evidence of incoherence. The refusal is triggered by the *combination* of a live-looking local window and an unprovable causal watermark, not by timestamp comparison alone. ## Operational Effect Treating temporal incoherence as a first-class refusal condition changes three operational behaviors. First, it forces every consumer to maintain a *causal* revocation watermark per issuer, not a wall-clock freshness check — the watermark must be a version vector or equivalent, because wall-clock freshness is exactly the signal that lies here. Second, it makes the federation's `max_clock_skew` a load-bearing configuration value: raising it to reduce false refusals directly widens the window in which incoherent tokens are honored, so it must be set from measured NTP/PTP bounds, not guessed. Third, it converts a class of silent policy violations into loud, attributable errors — the write that A forbade becomes a `TemporalIncoherenceError` at C, with the offending chain and watermark deltas attached, which is auditable and fixable, rather than a gap discovered during a post-incident review. The cost is availability: some fraction of legitimately-live tokens will be refused during revocation-feed lag. That fraction is bounded by the ratio of replication lag to token lifetime, and it is the correct trade — an instance that honors a token it cannot prove coherent is not more available, it is merely less honest about what it has done. ```python from dataclasses import dataclass from typing import Sequence class TemporalIncoherenceError(RuntimeError): """Raised when a delegated capability token is structurally valid but temporally incoherent across federation boundaries: no single instant exists at which all hops agree the grant was live and un-revoked.""" def __init__(self, reason: str, chain_id: str, detail: dict): super().__init__(f"[{chain_id}] {reason}: {detail}") self.reason = reason self.chain_id = chain_id self.detail = detail @dataclass(frozen=True) class Hop: org: str not_before: float # issuer-clock seconds not_after: float # issuer-clock seconds countersign_time: float # this hop's clock at countersign policy_eval_time: float # this hop's clock at policy evaluation snapshot_version: int # causal version of policy snapshot used @dataclass(frozen=True) class ConsumerView: now: float # consumer clock revocation_watermark_version: int # causal version of issuer revocation feed seen parent_issuance_version: int # causal version of parent grant issuance max_replication_lag: float # seconds, measured max_clock_skew: float # seconds, declared for federation def assert_temporal_coherence( chain_id: str, hops: Sequence[Hop], view: ConsumerView, ) -> None: """Enforce the coherence invariant before honoring a delegated token. Refuses (raises) when the token's apparent validity rests on a stale causal watermark or on clock skew larger than the remaining margin. """ if not hops: raise TemporalIncoherenceError( "empty delegation chain", chain_id, {"hops": 0} ) # Condition 4: consumer's revocation watermark must be causally newer # than the parent grant's issuance, else absence of revocation is unprovable. if view.revocation_watermark_version < view.parent_issuance_version: raise TemporalIncoherenceError( "stale revocation watermark", chain_id, { "watermark_version": view.revocation_watermark_version, "required_version": view.parent_issuance_version, }, ) # Condition 5: minimum remaining validity margin vs. max clock skew. margins = [h.not_after - view.now for h in hops] min_margin = min(margins) if min_margin <= view.max_clock_skew: raise TemporalIncoherenceError( "token within clock-skew shadow", chain_id, { "min_remaining_margin": min_margin, "max_clock_skew": view.max_clock_skew, }, ) # Cross-hop causal ordering: each hop's policy evaluation must not # precede the previous hop's countersign by more than skew budget. for prev, cur in zip(hops, hops[1:]): delta = cur.policy_eval_time - prev.countersign_time if delta < -view.max_clock_skew: raise TemporalIncoherenceError( "cross-hop causal inversion", chain_id, { "prev_org": prev.org, "cur_org": cur.org, "delta_seconds": delta, "skew_budget": view.max_clock_skew, }, ) if cur.snapshot_version < prev.snapshot_version: raise TemporalIncoherenceError( "attenuation against stale parent snapshot", chain_id, { "cur_org": cur.org, "cur_snapshot_version": cur.snapshot_version, "parent_snapshot_version": prev.snapshot_version, }, ) # All checks passed: the token is coherent and may be honored. return None ```