Hard carve-out on #552 (hash-first directory). Filing separately because it is a safety invariant and must not live as a bullet inside a performance ticket.
The rule already exists upstream
ciris-persist v38.7.0, src/federation/namespace/mod.rs:
every withdraw/revocation whose plane's tombstone_ceiling is Global (anti-rollback — a tombstone that relayed narrower than any copy could have traveled would starve holders, silently un-revoking)
Revocations travel at their plane's ceiling regardless of scope, precisely so a tombstone can never reach less far than the thing it retracts.
Why hash-first breaks it
The agent kill switch works by naming an agent's ID in a revocation that must reach it. Under hash-first retention a node would hold the hash of that revocation and fetch the body on demand.
That is an unexecuted kill order:
- a node that holds only the hash has not been killed;
- a node that cannot fetch — offline, rate-limited, no holder answering — silently un-revokes, which is the exact failure the ceiling exists to prevent;
- and it fails in the direction that matters least visibly: nothing errors, the agent simply keeps running.
Required
- Tombstones, revocations and withdrawals always retain bodies, at their plane's ceiling, unconditionally. Never hash-only, never fetch-on-demand, never rate-limited.
- Pin it with a test that fails if the class is ever folded into the general retention path. This is exactly the kind of special case a later refactor consolidates away innocently — and the consolidation would be invisible until someone needed a kill to land.
- State the reason at the retention seam. "Revocations are excluded" without "because a hash is not a revocation" invites the merge.
Scope note
This is edge-side retention policy. Persist already expresses the ceiling; nothing is needed from them.
Related: #552 · CIRISPersist tombstone_ceiling
Hard carve-out on #552 (hash-first directory). Filing separately because it is a safety invariant and must not live as a bullet inside a performance ticket.
The rule already exists upstream
ciris-persistv38.7.0,src/federation/namespace/mod.rs:Revocations travel at their plane's ceiling regardless of scope, precisely so a tombstone can never reach less far than the thing it retracts.
Why hash-first breaks it
The agent kill switch works by naming an agent's ID in a revocation that must reach it. Under hash-first retention a node would hold the hash of that revocation and fetch the body on demand.
That is an unexecuted kill order:
Required
Scope note
This is edge-side retention policy. Persist already expresses the ceiling; nothing is needed from them.
Related: #552 · CIRISPersist tombstone_ceiling