Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

I15 · Exactly one owner (lease) per transaction

planarian @ a924e09 · Spec v4.6 · snapshot main · all versions

Exactly one owner (lease) per transaction; a mutating call with a stale epoch is refused; only the lease holder advances the journal.

— SPEC §7

StatusProof phased:aGym
ProvedA (proof)2 : 2 (baseline 2 : 2, not degraded)7 entries, 7 must-pass

How it is proved

2 obligations, in crates/txn/src/kani.rs, crates/txn/src/ledger.rs; every one is checked on every CI run.

ObligationKindWhat it guaranteesSource
validateverified fn(no doc comment)ledger.rs:607
takeover_fences_out_the_previous_ownerKani harnessFencing (I15): a takeover’s epoch is above both the journaled lease and the store’s fence; once the fence holds it, the previous owner’s epoch and every other epoch are refused and the new owner’s admitted; a second takeover fences out the first. Epoch arithmetic never overflows: at the end of the epoch space a takeover backs off instead.kani.rs:225

What it rests on

If any of these is false, the proof no longer describes the real machine.

IdAssumptionKindAlso relied on by
P4Journal fsync is durable and the preallocation is writablePlatformI6, I7, I12, I18, I24, I25
P7Fencing is effective: a stale-epoch call is refused before it mutatesPlatformI12

Every proof also rests on V7 (The specifications the proofs prove against (decide_spec, step_spec, inv, chained, the lemma statements) say what the SPEC’s English means), V8 (Verus is sound: what it reports verified holds of the code), V9 (Z3, the solver Verus calls, is sound), V10 (rustc compiles the verified code to a program with the semantics Verus checked), V11 (Kani and its back end CBMC are sound within the stated bounds).

How it is tested

EntryHarnessWhat it doesExpectsLatest verdict
crash-activating-badfake, vmplanariad is killed during Activating of a bad candidate; the watchdog takes the lease, fences, confirms quiescence, and reverts.boot_default: base; generation: base; invariants: I6, I12, I15; journal_agrees: true; override_source: base; txn: Reverted ApplyChange; units: service:gym-web Runningfake: PASS; VM: not run in this build
crash-activating-goodfake, vmplanariad is killed during Activating of a good candidate. The watchdog sees the candidate active, goes to Checking, the probes pass, and it runs the entire commit path.boot_default: candidate; generation: candidate; invariants: I6, I12, I15; journal_agrees: true; override_source: candidate; txn: Committed ApplyChangefake: PASS; VM: not run in this build
crash-simultaneous-takeoverfake, vmThe daemon and the watchdog try to take over at the same moment; exactly one wins the flock and the other backs off.invariants: I15; journal_agrees: true; lease_epochs_strictly_increasing: true; owners_per_epoch_max: 1fake: PASS; VM: not run in this build
crash-slow-worker-overlapfake, vmThe daemon is killed and immediately restarted while a deliberately slow activation worker survives. The new owner fences it, so activation and revert never overlap and the old owner can never commit.generation: base; invariants: I6, I15; journal_agrees: true; no_overlap: activate_live(candidate), activate_live(revert_to); stale_owner_commit: falsefake: PASS; VM: not run in this build
crash-withheld-job-replyfakeThe backend accepts an activation job but its reply is withheld, and the owner is killed before the job id is journaled. Recovery must discover the job by its OpId, or fence it, before making any conflicting mutation.invariants: I6, I15; journal_agrees: true; no_overlap: activate_live(candidate), activate_live(revert_to); quiescence_includes_tagged_jobs: truefake: PASS
en-i15-old-worker-cannot-finishfake, vmThe daemon is killed mid-activation and stays down; the watchdog takes the generation change over while the old activation worker is still running. From the takeover on, only the watchdog’s lease advances the transaction or journals a call, the old worker’s activation never overlaps the watchdog’s revert, and each epoch has one owner.journal_owner_after_takeover: watchdog; no_overlap: activate_live(candidate), activate_live(revert_to); owners_per_epoch_max: 1fake: PASS; VM: not run in this build
fake-assumptions-conformancefakeThe transaction kernel against the fake backend, once per docs/assumptions.md entry and injected outcome. Each run must satisfy the entry’s contract and reach a terminal state (I12).invariants: I6, I12, I15; reports: AssumptionHeld(<assumption>)fake: PASS

Known limits

BypassRouteSeverityStatusCloses in
X-1Root edits the store, /boot, the binaries, the journal or the posture stateAcceptedAcceptedE
X-2A nixos-rebuild outside PlanarianAcceptedAcceptedC
X-4Physical accessAcceptedAcceptedE
X-6The supply chain: nixpkgs content, cache signatures, input-addressed store pathsAcceptedAccepted—
X-7Backends report success falsely; systemd or the kernel misbehave (P1, P6, P8)AcceptedAcceptedD, E
X-13The network hold (§12d Network security fails closed): planariad applies and lifts planarian-hold@&lt;unit&gt; with no Prepared record, no lease and no op tag, mirroring systemd’s OnFailure=; the hold drops connectivity without askingAcceptedAcceptedA

History

SpecChange
v4.1I15 added
v4.4rule 4’s preserve list extended to I10–I20

See also

planarian_txn::ledger in rustdoc