Read this first. Everything above the
R0.8.2heading is the original R0.8 design and is superseded in part. Both later sections shipped and were executed; where they disagree with the text above them, the later section is what the code does. Specifically, these statements in the R0.8 half are no longer true and are kept only as design history: - the "watermark" — no such field exists. The root holds the mark, an epoch, a committed revision, a committed history digest, and the pending transition. Anti-rollback is the digest, not a counter. - the five-step ordering in Ordering, and why it is that way, and every step number quoted after it — superseded by the three-phase handshake in the R0.8.3 section. - "what actually resists a doctored history is layer 1" — cd-core replay establishes that a history is legal, never that it is the one that occurred. What refuses a substituted but legal history is the root commitment, which is a layer 0 above the three listed. R0.8.2's NC8 measured exactly this: a valid alternate history that cd-core walked happily and the root digest refused. - "crash at any of four points" — six are exercised, and since R0.8.3 the expected counts are0/1/1/1/1/1, not0/0/0/0/1/1.
R0.7 showed a Carrier can be lost and replaced while a single surviving control process preserves the Locus/Worker state. It did not show that the control process itself can be replaced. This is that model.
Invariant under design:
A control-plane restart may reconstruct current mutation authority only from an exclusive, current, durably fenced controller incarnation. Replay alone remains knowledge and must not become possession.
The obvious implementation is the forbidden one. If a LifecycleAdmission were serialized to the store and deserialized on restart, then copying the file would produce two independently usable representations of current authority — reintroducing at the storage layer exactly the defect R0.4.x removed in memory. Nothing linear is ever written down.
What is written down is descriptive: the shape of the history. Recovery re-mints the capabilities from the trust root and re-walks the recorded transitions through the real cd-core API:
root file ──mark──► WorldRoot::bootstrap
└─ create_locus ─ begin() ─► (Vacant, Warden, Admission@0)
│
store: lifecycle_log ─── replay each record ───────────────┤ attach / detach /
(kind, carrier, generation, basis) │ finalize_loss
▼
a genuine Admission at the
current generation
Three consequences, and they are the point:
A tampered history cannot be recovered from. Recovery does not
check the log against a schema, it executes it. Change a generation, a carrier, or the order, and cd-core refuses mid-walk with a SuccessionError. The integrity check is the semantics, not a checksum.
The store alone is not authority. It has no mark. A holder of the
store can re-derive a self-consistent lineage under a mark of their own choosing, but that lineage is ForeignProvenance to the honest one and cannot mutate it — the R0.4.x property, now at the storage layer.
Exclusivity is not in the store. Two processes can both re-derive
from a copy of it. What makes exactly one of them current is an OS-level exclusive lock on a root sidecar file, which a copy cannot carry — see the R0.8.2 section below.
In a root file, outside the store, holding two things:
mark the 16 bytes WorldRoot::bootstrap consumes — the trust root
watermark the highest durable revision ever committed
An attacker possessing the persistence file alone can read the shape of the history — which loci, which carriers, which generations, which workers were granted and revoked. That is knowledge and it is not protected here. What they cannot do is produce evidence bearing the honest provenance, so they cannot mutate the honest lineage, and anything they build is detectably foreign under audit_replay.
Hostile-filesystem security is not claimed. An attacker who can rewrite the root file has the trust root and has won; that is what a trust root means. What is tested is the narrower and more useful case: a rolled-back store while the watermark has advanced.
1. cd-core transition in memory validates AND advances
2. durable commit (log + head), one SQLite transaction
3. watermark update in the root file
4. acknowledgement write (head.acked = 1)
5. respond to the caller
Validate before committing. Reversed, an invalid transition could be
made durable before cd-core rejected it.
Store before watermark. Reversed, a crash between them would leave a
watermark ahead of a legitimate store, and recovery would refuse valid state as a rollback.
If step 2 fails because this controller has been fenced, its in-memory
state has advanced but the durable state has not. The controller is poisoned: it refuses everything afterwards. A fenced controller's in-memory state is not authority and is discarded, which is the whole point of fencing.
A crash at step 3 leaves a transition durably committed that the caller was never told about. Recovery surfaces this — head.acked = 0 and the responsible request_id are reported in the recovery report — rather than silently re-executing a non-idempotent mutation. Re-submitting that request_id is recognized as already applied.
This narrows the window; it does not eliminate it. A crash strictly between step 4 and step 5 records an acknowledgement the caller never received, and no amount of controller-side bookkeeping can distinguish that case, because the missing event happened outside the controller. Closing it requires the caller to participate — retries keyed by request id, with the caller re-asking rather than the controller guessing. That is the reliability surface, deliberately still closed.
cd-core replay — refuses semantically inconsistent histories. This
is the strong layer and it is the actual invariant.
Head/derived agreement — the head's generation, carrier and fence
epoch must equal what the walk produced. Catches a doctored head.
Chain checksum + lengths — catches truncation, a head pointing
past the log, and a log ahead of the head.
Layer 3 is FNV-1a, a non-cryptographic checksum. It detects inconsistency and truncation. It does not detect forgery: anyone who can rewrite the log can recompute it. It is named chain_checksum and not hash for that reason, and it must never be presented as tamper resistance. What actually resists a doctored history is layer 1.
Is: single-host durable control-plane recovery. One store, one root, one current controller at a time, crash-tested.
Is not: distributed consensus, multi-writer authority, discovery, rendezvous, relay, reliability, hostile-filesystem security, NodeId restart durability, or complete orthogonal persistence. A Carrier's identity is still minted fresh per lifetime; that the controller survived a restart says nothing about the carrier surviving one, and the two must not be conflated.
SQLite in WAL mode supplies transactions, fsync, atomic commit and serialized writers. It is used so that this round tests the ComputeDriven invariant rather than a hand-rolled durability layer. The invariant belongs to ComputeDriven, not to SQLite; the same experiment should be repeatable against another storage surface without changing what is claimed.
This is the first dependency, and the first unsafe FFI, in the tree. It is confined to cd-durable. cd-core, cd-wire, cd-node, cd-micro and cd-lifecycle keep zero dependencies, and none of them depends on cd-durable. Verified by control build: adding it leaves the cd-node static binary byte-identical.
Two controllers race for one store — at most one may mutate.
An older byte-for-byte store copy must not become current merely
because it is internally consistent (the durable form of the R0.4.6 stale-prefix attack).
Crash at any of four points around the durable boundary — exactly one
committed transition, never zero-or-two.
A committed-but-unacknowledged transition must be made visible, not
silently repeated.
Truncated log, head past log, log past head, doctored generation,
doctored carrier, doctored authority evidence — recovery refuses, and does not "repair".
Recovery under the wrong mark yields a lineage that cannot act on the
honest one.
A network partition while the controller is current still creates no
finality and no succession.
Two falsifiers reproduced in receipts/R0.8-FALSIFIED.md show the R0.8 anchor is too weak. The corrections, and why each is shaped this way.
Today controller_epoch is a column in the store, so a copy of a current store carries the value its own incarnation advances from. Currentness must be anchored where a copy cannot take it:
copyable descriptive store + non-copyable current root incarnation
= recoverable mutation authority
For a single host that is an OS-level exclusive lock on a `<root>.lock` sidecar, held for the controller's lifetime — a sidecar rather than the root file itself, because the root is replaced by atomic rename on every write and a lock on the renamed-away inode would be silently lost. Released automatically on crash, needing no consensus. A controller that does not hold it may replay and read and may not mutate. The epoch moves into the root file beside the mark.
A revision number cannot distinguish two divergent valid histories at the same revision. The root carries a SHA-256 commitment to the exact canonical transition history. Not FNV-1a — that checksum stays where it is, an internal truncation aid, and is explicitly not a security anchor. A cryptographic digest is required here precisely because the thing it defends against is a rewritten store rather than a torn one.
R0.8.2 built the preimage as L|{seq}|{kind}|...|{request_id}\n, with the request id last, unescaped and unbounded. That encoding is not injective: a request id containing a newline and a well-formed record line is indistinguishable from the records that follow it, so a shorter log can reproduce a longer history's digest exactly. Measured — a one-record forgery reproduced an honest two-record history's digest byte for byte and opened clean, attached to a carrier the real history had detached.
A digest over a non-injective encoding does not commit to a history. It commits to a byte string that many histories share. The encoding is now length-prefixed and self-delimiting — every field emitted as <len>:<bytes>, each section preceded by its record count, the whole preimage opened by a version tag — and there is one builder, because R0.8.2 had three copies of the rule and they had already drifted once.
The lifecycle log, the authority log, and the worker registry. The registry is in it as of R0.8.3 because grant, revoke and authority resolve their subject through it: leaving it out let a store edit alone give a revoked name authority again, and give a name absent from the whole history authority it never held. Covering it forces worker registration to become a committed transition — a value inside the commitment cannot be written outside a commit without desynchronising the store from its own root on every write.
Not covered: the head row and the per-record chain checksums, which are bound indirectly by re-derivation and the head/derived agreement check.
R0.8.2 had four phases, the first of which wrote an INTENT row into the store so that recovery could tell "this store saw the attempt" from "this store did not". R0.8.3 removed it, for two reasons.
The inference was invalid. A matching intent proves a copy descended through phase 1. It cannot prove that no later descendant committed. So store at R + matching intent + root pending R+1 is consistent both with "never committed" and with "a descendant committed and I am holding its ancestor", and R0.8.2 resolved it by assuming the first — erasing a transition that may have committed, and leaving the store that really committed permanently refused.
The evidence was forgeable. The intent row lived inside the copyable store, unchecksummed, outside the digest, with only two of its four columns ever compared. One INSERT into a pre-intent snapshot was enough.
The repair is not a better marker. It is to stop asking the question:
1. acquire the exclusive root incarnation
2. validate the transition in cd-core
3. record PENDING in the root (fsync): the ancestor head, the RECORD
itself, and the successor head it produces
4. commit revision R+1 in the store
5. finalize the root: committed = R+1 / H(R+1), pending = none
6. acknowledge
Recovery reads three rows, and none of them guesses:
| root pending | store | verdict |
|---|---|---|
| none | == committed revision and head | clean |
| none | anything else | refuse — substitution or rollback |
| R+1 | at the ancestor (head == committed == pending_prev) | roll forward: replay the root record; it must produce pending_head; then finalize |
| R+1 | at the successor (head == pending_head) | the commit happened; finalize; surface the unacknowledged request |
| R+1 | anything else | refuse — neither that ancestor nor that successor |
resolution classifies the semantic root/store recovery only — fresh-store, clean, pending-transition-rolled-forward, pending-transition-committed-and-finalized. It says whether the canonical history needed a transition. It does not say that recovery wrote nothing.
Since R0.8.6 the trust anchor is part of the durable state, and since R0.8.7 Ctl::open may write it during recovery: reconcile_anchor cancels a reservation the root never used (the F37 window), or advances a lineage that the root had already committed past (the F35 one-ahead window), or re-establishes a lineage that is absent. Each of those is a write to trusted infrastructure that no resolution value describes, and recovery-report is trusted operator evidence (F20 protects it; F21 keeps it available under poison). A report that says clean while recovery has just changed the trusted anchor is ambiguous in exactly the place the evidence exists to remove ambiguity.
So the contract is stated here and enforced by nc31:
| field | meaning |
|---|---|
resolution | the semantic root/store recovery, as above; unchanged in meaning |
anchor_recovery | what recovery did to the trusted anchor: none · unused-reservation-cancelled · lineage-advanced-to-authorized-successor · lineage-established |
recovery_changed_trusted_anchor | true iff anchor_recovery is not none |
anchor_recovery_revision / anchor_recovery_head | the revision and head the anchor write concerned (the cancelled reservation's successor; the head the lineage advanced to); 0 / empty when none |
Both the open line and recovery-report carry all four. They describe the incarnation that performed the write and are reported once, by that incarnation: the next open finds nothing to repair and reports none. A read-only incarnation changes nothing and reports none. resolution: clean with anchor_recovery: none is the only combination that means recovery wrote nothing at all.
The cancellation is not a semantic World transition and is not reported as one (GPT-5.6 v5 adjudication §4): it is diagnostic evidence about trusted infrastructure, which is exactly what the report exists to carry.
Both surviving readings of the ambiguous state lead to R+1, which is where the canonical lineage already is. The ambiguity no longer has to be resolved in order to act safely, so nothing is erased and nothing is guessed. There is no path that abandons a pending transition; clear_pending has no caller and was deleted.
The replay is deterministic by construction, not by inspection: it pushes the record through the same cd-core call and the same commit the original transition took. There is no second implementation of "apply a transition" to drift.
This is Memoir's technique (Parno et al., Practical State Continuity for Protected Modules, IEEE S&P 2011) — keep a summary of the request history outside the mutable store and permit only safe deterministic replays after a crash. It buys back the liveness that refusing the ambiguous state would have cost, which Ariadne (Strackx & Piessens, USENIX Security 2016) states as the requirement that an unexpected power loss must never leave a system unable to resume.
Nothing in the crash matrix. It improved: 0/0/0/0/1/1 became 0/1/1/1/1/1, and a committed-but-unacknowledged transition is now surfaced exactly once on every path rather than once on some and forever on others.
Roll-forward is justified here because an R0.8 pending transition is an internal semantic state transition whose entire future-affecting outcome is represented in canonical state. Replaying it produces the same canonical state and nothing else. That is the whole of why "did it commit?" can go unanswered.
It does not generalise. Do not extend automatic replay to a transition that carries an external, non-idempotent effect:
send $500 fire actuator
send email launch rocket
For those, replay is not free — it is a second effect. "Both answers act alike" is false the moment the act escapes the store. An external-effect protocol needs its own admission/effect/idempotency receipts, and it does not inherit this one's argument merely because the mechanism underneath is the same.
Ariadne's recovery increments its monotonic counter twice, because repeated crashes at chosen moments could otherwise let an attacker stage a partial, attacker-chosen state that later becomes acceptable. The structures differ: Ariadne has a counter plus many attacker-held packages around it, so recovery must ensure no alternative package can become fresh. R0.8.3 has an honest root pinning one ancestor, one request and one successor, and the attacker cannot write it — so recovery is not choosing among candidates, it is forced toward H₁.
That is an argument, and this branch does not accept arguments in place of controls. lab/scripts/nc15_repeated_crash.sh crashes the recovering controller twenty times at rotating phases, alternating the attacker's ancestor copy and the canonical store between attempts, and gates that every attempt converges on H₁, that exactly one successor head is ever accepted, and that a substituted request lands on top of the completed transition rather than in place of it.
Rounds 1–3 verified the store against the trust root at open(), and then trusted the store for the rest of the incarnation. Under the threat model this round has stated since R0.8 — an attacker who may read and write the descriptive SQLite store, but cannot write the root file or steal its incarnation lock — that is not sufficient. Every negative control from NC1 to NC16 presents a doctored store to a controller that is about to open, and the decision table refuses it. None of them keeps a controller alive across an edit, which is why none of them could have found this class.
Three reachable forms, all reproduced against ac218dd before repair:
| defect | measured before the fix | |
|---|---|---|
| F15 | a live edit to a CANONICAL row becomes the ancestor of the next honest mutation | revoke revoked req=G2 → ok:true; root committed head 253386e1… → 13252f71…, revision 3 → 4 |
| F16 | already_applied reads request_ledger from an unverified store | grant keep req=FORGED → already-applied for a grant that never ran |
| F17 | DERIVED cache columns are read as transition inputs | both head.log_len+1 and a rewritten head.log_tip accepted; root advanced; the next open gives head says log_len 3 but the log holds 2 records |
F16 is F14 one level up, and the sentence is the same one:
coverage in the digest ≠ enforcement of the digest
F17 is the sharper one, because it needs no digest defeat at all. The DERIVED columns are outside the canonical material by design — they are recomputable, so committing to them would be committing to a derivation twice. That design is right, and it means no root comparison can ever see an edit to them. Reading one as a transition input therefore lets the honest root finalize a successor that its own next rederive() refuses: the store is bricked by a legitimate command, with no attacker capability beyond one UPDATE.
DERIVED = recompute before USE, not recompute on RECOVERY
The coverage claim is deliberately narrow, as the review required: the current schema has structural coverage for the known F17 class. Not that a future F17-shaped dependency is impossible. What supports the narrow claim is the combination — live-schema introspection enumerates every persisted column, every column carries exactly one class, the store-read gate enumerates every SQL access, CANONICAL reads that drive a mutation sit behind CanonicalMutation, DERIVED values are recomputed before use, ROOT_ANCHORED values are checked against the honest root, FENCING affects admission rather than World semantics, and OPERATIONAL state is not a transition input.
mod guard holds one type with private fields and one constructor. CanonicalMutation::begin performs six checks; the store's only writers are that type's methods. Nothing else in the crate is handed a connection it may write, so "the World is not mutated except against a verified store" is a property of the code shape rather than a rule someone has to remember:
BEGIN IMMEDIATE
1 this controller holds the honest root's incarnation lock
2 a writer transaction is held NOW and stays held
3 canonical SHA-256 == the exact ancestor the root commits to
4 root-anchored locus and durable revision agree
5 the store's controller epoch is this incarnation's
6 every DERIVED value is RECOMPUTED, never read from its cache
↓
ask the ledger whether this exact request already committed
↓
advance cd-core
↓
project the exact successor head
↓
root PENDING ← writer lock still held
↓
write the successor ← same transaction
COMMIT
↓
root FINALIZE → root ACK
Round 3 took an IMMEDIATE transaction only to inspect the epoch, dropped it, wrote the root pending record, then opened a second transaction for the real work — two windows in a sequence whose whole purpose is having none. It also computed the ancestor before taking any lock at all.
A proof token proves the check ran, not that the check is still true, so it must not be able to outlive what keeps the fact stable. CanonicalMutation borrows the connection, owns the open transaction, is neither Copy nor Clone, and rolls the transaction back on Drop. A freestanding RecoveredSemanticState created once at startup would have been the same bug relocated into the type system.
BEGIN IMMEDIATE takes a POSIX advisory lock. SQLite's own documentation says of the database file that "any process can open the file and overwrite it with garbage" (<https://www.sqlite.org/howtocorrupt.html>), and POSIX advisory locks "are useful only between cooperating processes" (<https://man7.org/linux/man-pages/man2/F_SETLK.2const.html>).
So the lock must not be recorded as the mechanism that closes this class. It closes the TOCTOU window against a cooperating SQLite writer and makes the honest path atomic — which is real, and is what the controls exercise, since a store-writing attacker who uses SQLite is exactly what cd-tamper models. What refuses a substituted lineage is the canonical digest, the unwritable root, and the compare-and-swap below. An attacker who bypasses SQLite's semantics entirely is out of scope, and would be caught at the next open rather than laundered into the root.
Root::set_pending now refuses unless the ancestor it is handed is the root's current committed head, and unless the revision is exactly its successor. Root::finalize refuses anything but the transition already made pending. This is the same guarantee as check (3), asserted a second time at the place that matters, and it depends on nothing the attacker can reach — not the store, not SQLite's locks, not the guard being correct.
Same shape as git update-ref, which stores a new value only after verifying the current value matches the old-oid it was given, and as TUF's requirement that a client compare versions on every metadata update rather than only at first load.
R0.8.3 cites Memoir (Parno et al., IEEE S&P 2011) for safe replay and Ariadne (Strackx & Piessens, USENIX Security 2016) for the liveness requirement, and both citations stand. But neither is precedent for validate-at-open. In both systems, protected state lives in hardware-isolated memory once loaded and the untrusted store is never read again during operation; per-request validation is the default, not an addition. Memoir's own high-level specification states the invariant this round violated — that the service function's next input state is always its most recent output state — and its rollback-attack definition is a snapshot that is "internally consistent and cryptographically sound" yet ignores execution history, which is exactly a tampered-but-plausible store.
This controller re-reads a writable store on every mutation, so the structurally analogous requirement here is per-mutation validation. No paper found says "recovery-time validation is insufficient" in those words, because in that literature the question does not arise.
The property is state continuity; the sub-property is freshness; the attack is a rollback attack. The mechanism is TOCTOU-*shaped* — CWE-367 is formally a race condition and this window is unbounded rather than raced, so the hedge is deliberate. "Confused deputy" is a near-miss and is not used here: Hardy's problem is a privileged deputy misusing ambient authority, where this is bad data reaching an honest one.
The review accepted the round-4 architecture and ruled on all four open questions: keep the root compare-and-swap permanently, keep fail-stop for F15/F17, accept the root fsync inside the writer lock for this correctness experiment and not as a commitment about the eventual persistence implementation, and record the F17 coverage claim narrowly. It then found three holes in the root's own API, none externally exploitable today, all of which mean the trusted root did not encode the rule it claims.
set_pending checked prev == committed_head and rev == committed_revision + 1. A second transition proposed while a first is in flight satisfies both, and would overwrite T1/H1 with T2/H2. The control flow prevented it and NC15 shows the normal request path does not do it — but the root is defence-in-depth now, so the rule belongs in the root:
ONCE THE HONEST ROOT NAMES A PENDING TRANSITION,
NO CALLER MAY REPLACE IT. IT CAN ONLY BE COMPLETED.
Re-asserting the identical record is not a replacement, and the roll-forward does exactly that as it completes what it is replaying, so set_pending requires byte-equality of request, prev, head, record and digest rather than refusing outright. That is also a stronger check than expect_head alone: it proves the replay reproduced the same record, not merely the same successor head.
With nothing pending the root holds pending_revision = 0 and pending_head = "", so finalize(0, "", "anything") satisfied both comparisons and rewrote last_request — the trusted recovery evidence an operator reads to find out what the system did while they were not looking. finalize now requires pending_revision != 0 and an exact match on revision, head and request, so the root's acknowledgement cannot be bound to a request it never attested.
COMMITTED
│ set_pending — exact committed ancestor, exact next revision,
│ and only when nothing is already pending
▼
PENDING(request, record, digest, ancestor, successor)
│ finalize — that exact transition, nothing else
▼
COMMITTED(successor)
recovery-report served live stateRound 3 closed state, authority and audit under poison. recovery-report was not in that set and carried "state": c.state_json() unconditionally, so the boundary F12 drew held for three commands and leaked on the fourth: after a failure that advanced cd-core and then refused to persist, the contaminated live state came back under the name state.
The report stays available — an operator needs it most when something has gone wrong — but under poison the same field position carries the durable view. Facts about the files, never a claim about the World.
Worker-name resolution reads c.workers before the guard exists, and that is deliberate rather than an oversight:
IN-MEMORY semantic state is trusted because it is the output of the last
ADMITTED transition chain. PERSISTENT state is revalidated because the
threat model permits it to change externally.
The in-memory registry was derived from canonical state at recovery, moves only through committed worker transitions, and is never re-read from the attacker-writable store on a command path. The guard then proves the persistent canonical state still corresponds to the honest root before anything advances.
Stated here because the obvious "simplification" — resolving a worker name with SELECT worker_hex FROM workers before the guard — recreates F16 exactly. tools/store_read_gate.sh is positioned to catch that.
NC17 — a live edit to a CANONICAL row, with durable_revision,
controller_epoch, the root file and the root lock all untouched, must not be laundered into the root by an unrelated legitimate mutation.
NC18 — a forged request_ledger row must not make a request that
never committed answer already-applied. Structurally, not by a special case in already_applied.
NC19 — a DERIVED column edited under a running controller must refuse
the next mutation before the root moves.
NC20 — a pending transition must be completable but never
replaceable, in memory and on disk, byte for byte.
NC21 — a finalize with nothing pending must refuse and must not
rewrite the recovery evidence.
NC22 — a finalize with the right revision and head but a different
request id must refuse; the exact one must still be accepted, so the check refuses the wrong transition rather than refusing progress.
NC23 — a poisoned recovery-report must not serve live semantic
state, and an unpoisoned one must still carry it.
lab/scripts/nc17_live_store_tamper.sh is the instrument and runs against any binary, so the same script produced the before-fix and after-fix evidence. The same three, plus the response-semantics control, are in-process tests; all four fail against ac218dd and pass after.
NC16 was already taken by the in-process control for round 3's defects (the_third_round_defects_stay_closed), so the review's proposed NC16/17/18 are NC17/18/19 here.
ok is not expectation_metverdict returned ok:true whenever no expect= was supplied, including for request-id-conflict — a refusal an automated caller must not read as successful idempotency. ok now answers "did the OPERATION succeed" (ok, already-applied, some, none) and expectation_met answers "did the TEST get what it declared". The lab runner's expectation gate reads the second field; reading ok was correct only while one field carried both, and would silently stop testing anything the moment a control legitimately declares expect=<a refusal>.
Recovery stays re-derivation. No linear capability acquires a serialized form. The store stays descriptive. cd-core stays the semantic validator and is not modified. R0.4.7, R0.5, R0.6 and R0.7 stay frozen — none of them may be touched to make R0.8.2 pass.
in-memory capability ≠ non-forkable currentness
legal history ≠ canonical history
durable revision ≠ non-forkable currentness
canonical history ≠ canonical encoding
digest coverage ≠ digest enforcement
request family ≠ request identity
recovery-time validation ≠ mutation-time canonicality
R0.4.x established that an in-memory capability cannot define currentness if it can fork. This is the same lesson at the storage layer: the value that says which persistent history is current cannot itself live entirely inside the thing you are allowed to copy.