Repo: /home/dylon/Workspace/f1r3fly.io/libdictenstein · 2026-06-02 · implementation-ready. Fixes a real
data-loss bug blocking R-B (overlay delete) and the lock-free flip. ZERO new unsafe. Phased, reversible,
green-gated. Persisted from the Plan-agent design (full prose in the session transcript).
Order-A writes in two UNLINKED steps: append (LSN order ≺_LSN) — append_to_wal_returning_lsn
(wal_helpers.rs:73)→WalWriter::append (writer.rs:169, lsn=next_lsn.fetch_add(1) then write under file
lock) — then visibility CAS (commit order ≺_CAS) — the separate compare_exchange on lockfree_root
(insert_cas_durable:288/remove_cas_durable:438). Nothing forces ≺_LSN == ≺_CAS. Recovery replays in physical/
LSN order into the OWNED tree (mmap_ctor.rs:400-423, every ctor sets lockfree_root:None; enable_lockfree
rebuilds overlay FROM the owned root, so REC-A inherits the owned replay), strict last-writer-by-position. The
committed VISIBLE overlay is LWW under ≺_CAS.
Violated invariant ReplayEqualsCommittedVisible: LSN-ordered-replay membership must equal CAS-order committed
visible membership. s019 trace: WAL …Insert@352, Remove@356; CAS last-writer = Insert (PRESENT) but
highest-LSN record = Remove → replay ends absent → acknowledged net-present key LOST = data loss. REAL bug (the
quiesced overlay is a well-defined committed history), not a test-oracle bug.
Why insert-only is accidentally safe: inserts are idempotent+monotone (any replay order → same set); the
existing concurrent_durable_writers_all_survive_reopen passes. Remove makes $insert\cup remove$ order-sensitive +
non-monotone → divergence becomes loss. General Order-A hazard for ANY non-monotone op (remove, future
upsert/decrement-increment). Existing specs miss it: LockFreeOverlayRemoveCas has no WAL/replay;
LockFreeDurableCheckpoint!NoLostWriteUnderLockFreeCommit tracks LSNs as opaque tokens, never collapses two LSNs
of one term through replay. Secondary hazard H2: the direct Immediate append does fetch_add then separately
takes the file lock (writer.rs:170 vs :207) → WAL physical order can differ from LSN order; the explicit
(gen,lsn) sort (below) fixes this too (group-commit already orders via submit_order).
≺_CAS is not recorded anywhere durable; the
natural "highest-LSN per term" rule gives the WRONG answer (picks Remove@356). Any real fix must add $\ge$1 ordering
datum to the durable record $\Rightarrow$ that IS approach C.Idea: durably record enough of ≺_CAS to recover per-term LWW. The minimal statistic is a per-term commit
generation assigned at CAS-success; replay picks, per term, the record with max generation (ties by lsn) and
applies only its effect. Generation in ≺_CAS order $\Rightarrow$ "max gen per term" == CAS-order last-writer == committed
visible $\Rightarrow$ ReplayEqualsCommittedVisible by construction, for ALL mixed histories (future-proofs upsert/increment).
Realization (single data append + a conditional rank marker; Order-A preserved):
Insert{term,value}/Remove{term} → lsn (durable before
visible).g = node.version
(overlay/node.rs: as_final/as_non_final do version = loaded_child.version + 1, so successive winners on
a term's leaf are strictly increasing — the monotonicity theorem §3.6).CommitRank{data_lsn:lsn, term, generation:g}
binding the durable data record to its commit generation.mark_committed(lsn) AND mark_committed(rank_lsn); cache update; return.
Replay (NEW reconcile, both mmap_ctor.rs sites → ONE shared replay_records_lww): pass 1 build
rank: HashMap<Lsn,u64> from CommitRank records; pass 2 per-term keep the data record with max
generation_of(lsn)=rank.get(lsn).unwrap_or(lsn) (ties by lsn), apply its effect via *_impl_no_wal. CommitRank
is a membership no-op (like Checkpoint). Honor the checkpoint_lsn skip by data_lsn. The explicit (gen,lsn)
sort also closes H2 (no longer trusts physical order). Key the term map on raw Vec<u8> (avoid lossy collisions).Why a separate marker, not a field in the data record: g is unknown at step 1 (Order-A forces the data record
out before the CAS); back-patching a synced frame violates append-only durability. The node-version + post-CAS
rank-marker needs no back-patch. (Rejected: a global commit counter patched into a reserved slot — needs back-patch.)
§3.6 LOAD-BEARING THEOREM (gen monotone in ≺_CAS per term): read g from the EXACT leaf Arc the op published
(returned by try_*_lockfree_path; nodes immutable, only the root pointer swaps) — NOT by re-walking the live root
(stale-read hazard). Idempotent AlreadyExists/AlreadyAbsent arms publish nothing → record g = current published leaf.version under the same enter_read() pin; if it races a later op, the later op has a strictly higher version
and wins replay — the no-op being out-ordered is harmless. Loom-checked + TLA CommitCas action.
Signatures/sites: (a) codec.rs — add WalRecordType::CommitRank=15 + variant CommitRank{data_lsn:Lsn, term:Vec<u8>, generation:u64} + serialize/deserialize/serialized_size/TryFrom arms + WalHeader version bump.
Existing variants byte-identical $\Rightarrow$ existing WALs read unchanged. (b) wal_helpers.rs — reuse
append_to_wal_returning_lsn (optional thin append_commit_rank wrapper). (c) insert_cas_durable:289/(d)
remove_cas_durable:439 — emit CommitRank after CAS (read published-leaf version), mark both LSNs; extend
LockfreeRemoveResult::Removed(Arc<OverlayNode<V>>) to carry the leaf. (e) mmap_ctor.rs:400-423+:688-709 →
shared replay_records_lww (removes the duplication = no-drift). (f) recovery.rs:182 — $CommitRank \Rightarrow vec![]$
no-op arm (preserves REC-A replay-completeness). (g) mark_committed UNCHANGED (keys on data LSN; watermark/
NoLostWriteUnderLockFreeCommit untouched).
§3.4 WAL-format change is REAL + REQUIRED (§2D proves visibility order isn't otherwise durable). Additive +
back-compat: backward (new code, old WAL) — no CommitRank $\Rightarrow$ generation_of=lsn fallback = today's behavior;
existing logs are insert-only/pre-remove so the fallback is safe for every log that can exist; NO migration.
forward (old code, new WAL) — bump WalHeader version so an old binary refuses the file fail-closed (not
silent truncation). Opt-in (enable_lockfree + durable policy), pre-flip; document the one-way header bump in
GAP_LEDGER/UNSAFE_BOUNDARY. Matches the additive Version* records 12-14.
§3.5 Order-A/watermark preserved: data durable-before-visible (steps 1→2 unchanged); ack now also waits for the
rank sync (STRENGTHENS Order-A); checkpoint_lsn=committed watermark unchanged; IoError window — data durable, no
rank, watermark not advanced → recovery replays under gen=lsn fallback (correct for the single uncommitted op).
§3.7 General (records ≺_CAS for every op; reconcile is content-agnostic). §3.8 REC-A auto-fixed (overlay
rebuilds from corrected owned replay); fix touches ONLY the owned replay; REC-B must reuse the reconcile.
NEW spec LockFreeOverlayDurableReplay.tla (+.cfg+_Unsafe.cfg) — bounded (Terms={a,b}, MaxOps $\approx$ 4, lsns/gens
1..6). Vars: nextLsn,nextGen,wal(seq of Insert/Remove/Rank), present/removed (visible, same abstraction as
LockFreeOverlayRemoveCas), committed, replayed. Actions: Append(t,kind) (step1, no visibility change);
CommitCas(t) (step2, update present/removed LWW + assign gen'=nextGen[t]+1); AppendRank(t) (step2.5, then
$committed'\cup ={lsn,rankLsn}$); CrashRecover (replayed[t]=effect of max-gen data record, gen=rank else lsn, ties by
lsn, over committed $\le$ frontier). USE_COMMIT_RANK=TRUE (design, replay by gen) / =FALSE (_Unsafe.cfg
negative control, replay by lsn = the broken scheme). Invariants: ReplayEqualsCommittedVisible ($\forall$t:
(t $\in$ replayed)<=>(t $\in$ present)) [headline]; NoLostNetWrite (present $\Rightarrow$ replayed, the s019 direction);
NoResurrectionOnReplay ($\neg$present $\Rightarrow$$\neg$replayed); reuse DurablePrefix. The _Unsafe.cfg MUST violate
ReplayEqualsCommittedVisible via the s019 trace (Append Insert@a, Append Remove@b>a, CommitCas(Remove) then
CommitCas(Insert) $\Rightarrow$ present={s} but lsn-replay ends Remove $\Rightarrow$ replayed={} $\Rightarrow$ FALSE<=>TRUE). If the unsafe cfg passes,
the control is broken $\Rightarrow$ fail the gate. Register in verify-formal-correspondence.sh SANY(:252)+TLC(:303)+
negative-control(:335). Do NOT weaken the existing specs (compose, don't replace).
Deterministic Rust regression replay_orders_by_commit_rank_not_lsn (+ resurrection-polarity twin): force the
s019 interleaving deterministically (two Barriers / a controlled scheduler so WAL=Insert@a,Remove@b while CASes
land Remove-then-Insert), drop-no-checkpoint, reopen, assert contains("s019")==true. FAILS pre-fix (OD2 reverted),
PASSES post-fix — the differential proves the test has teeth. Seeded + #[serial].
Empirical soak gate: run concurrent_durable_mixed_insert_remove_reopen_equals_live_set (lockfree_cas.rs:2213)
$\ge$50$\times$ green (Immediate + a GroupCommit twin). Pre-fix fails within ~48 attempts; post-fix $\ge$50$\times$ clean.
Stay green: concurrent_durable_writers_all_survive_reopen (insert-only), recovery_replay_completeness_ correspondence, persistent_{artrie,wal,vocab_wal}_* atomicity/recovery; full gate exit 0; 0 new unsafe.
\ge$2504 + verify-formal-correspondence exit 0 + unsafe-inventory exit 0; systemd 32G + real-disk; RUN_TLC=1 for the gate)CommitRank=15 type+variant+ser/de/size+TryFrom + WalHeader version bump +
recovery.rs no-op arm + codec round-trip unit test (old-record bytes unchanged). No producer/replay change.
Rollback: delete variant.mmap_ctor sites → shared replay_records_lww with
(gen,lsn) ordering, gen=lsn when no rank $\Rightarrow$ behavior IDENTICAL for existing WALs. Unit tests on hand-built
record vectors (incl. a synthetic rank). Gate: all recovery/atomicity correspondence green (proves behavior-
preserving). Rollback: revert to in-order loop.Removed(Arc). Rollback: drop rank append (consumer falls back to LSN order).LockFreeOverlayDurableReplay.tla+cfgs; ReplayEqualsCommittedVisible
passes; USE_COMMIT_RANK=FALSE negative control FIRES on s019. If not → fix is wrong, STOP.\ge$50$\times$ green (Immediate + GroupCommit). Unblocks R-B + the flip.
OD0-OD2 reversible by deletion; OD3-OD5 verification-only. No irreversible step except the WalHeader version
bump (fail-closed downgrade, gates an opt-in pre-flip feature — no released format broken).benches/lockfree_flip_benchmark.rs, gate on acceptable regression. (B trades this for lock contention.)g from the exact published LEAF Arc (not a re-walk/ancestor);
loom schedule ("rank monotonic under concurrent same-key insert‖remove") + TLA CommitCas check it.\Rightarrow$ watermark stalls
at data LSN, safe); checkpoint subsumes sub-watermark ranks (reclaim with data records); REC-A auto-fixed; REC-B
must reuse the reconcile. LockFreeDurableCheckpoint[Eviction] specs stay green unchanged.Vec<u8> (not lossy-UTF8) to avoid collisions.replay_records_lww (the TLA-corresponding impl); if the
refactor is declined, patch both identically (a hazard the design recommends against).src/persistent_artrie_core/wal/codec.rs (CommitRank=15 type+variant+ser/de/size/TryFrom; WalRecordType:15-86,
WalRecord:90-204, serialize_payload:230; WalHeader version)src/persistent_artrie_char/lockfree_cas.rs (emit CommitRank: insert_cas_durable:289-302,
remove_cas_durable:439-454; LockfreeRemoveResult::Removed(Arc):496; soak :2213)src/persistent_artrie_char/mmap_ctor.rs (replay sites :400-423+:688-709 → shared replay_records_lww;
checkpoint skip :402/:690)formal-verification/tla+/LockFreeOverlayDurableReplay.tla+.cfg+_Unsafe.cfg (ReplayEqualsCommittedVisible
scripts/verify-formal-correspondence.sh:252/303/335)src/persistent_artrie_core/recovery.rs (recovered_operations_from_record:182 — $CommitRank \Rightarrow vec![]$)Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |