Status: REDIRECT BLOCKED on a COUPLED PACKAGE: (1) genericize the overlay counter applier over V, AND (2) a #41-aware recovery-checkpoint-reopen watermark fix. Both data-loss-critical, each needs its own red-team. The investigation UNCOVERED A CONFIRMED PRODUCTION DATA-LOSS BUG (u64 recovery→checkpoint→reopen doubles counter deltas) — see docs/design/recovery-checkpoint-reopen-double-apply-bug-2026-06-08.md.
⚠️ CORRECTION — "L1.4 refuted" (below) was ITSELF wrong (a masking artifact). My first TDD pass found the i64 guards GREEN and concluded L1.4 (watermark seed) was unnecessary. WRONG: the green was because the u64-only overlay delta applier NO-OPS for i64 (the bug masking the bug). The generic-V applier fix unmasks it, AND a
u64diagnostic CONFIRMED the double-apply is real in production (Some(8)for a recovered+4). So L1.4 (a watermark fix) IS genuinely required — but the naivemark_committed(max_lsn_in_segments)seed violates the #41 capture-ordering invariant ($watermark \le synced frontier$; fresh-WAL frontier=0 → panic at overlay_checkpoint.rs:295), so the real fix is the deep #41-aware change in the bug doc.⛔ REDIRECT BLOCKER (2026-06-08, TDD-caught — the agent's "parity" claim was empirically FALSE): the naive swap
apply_recovered_operation_no_wal→apply_recovered_operation_overlay(L1.1) was implemented and FAILED the committed oraclebyte_corruption_rebuild_replays_batch_increment_and_cas(i64 insert+increment → expected 5, got dropped). Root cause:overlay_eligible_v()==trueunconditionally (overlay_write_mode.rs:487), so a byteV=i64trie DOES flip to the overlay, butapply_recovered_operation_overlay's Increment-DELTA arm (flip.rs:1166) routes throughoverlay_publish_counter/overlay_counter_get, which are hardcoded to the<u64, S>monomorph via anAnydowncast (overlay_write_mode.rs:547/561) and silently NO-OP forV=i64(and any non-u64counter). The OLD path (ownedapply_recovered_operation_no_wal+ the STRUCTURALreestablish_overlay_from_owned/build_overlay_root_from_owned) was generic over V, masking this; the redirect's PER-OP overlay counter applier is u64-only. (Normal non-recovery i64 increments work — they use the genericincrement_casdirectly; only the RECOVERY/reestablish per-op counter path is u64-specialized.) $\Rightarrow$ PRECONDITION: makeapply_recovered_operation_overlay's Increment-delta (and the absolute arm'soverlay_publish_counteruse) GENERIC over V — read the current leaf value generically (0 if absent), add the delta via the i128counter_codec, publish viaoverlay_publish_value(generic). This touches the i128 counter codec (a DOCUMENTED past BLOCKER — see memorycounter-u64-restoration-done) AND the SHARED applier (the normal-reopen Overlay arm uses it too), so it is data-loss-critical and needs its own red-team before the redirect lands. The owned applierapply_recovered_operation_no_waltherefore CANNOT be deleted at L1.3 yet — it is the generic-V recovery path until the overlay counter applier is genericized (this also touches the G1–G5 overlay-V-genericization track). Reverted commit-clean; guards retained (tests/persistent_recovery_watermark_seed_l14.rs— they PIN both the no-double-apply AND the create-on-missing/i64 properties the redirect must preserve).(SUPERSEDED design assumption) L1.4 EMPIRICALLY REFUTED + DROPPED:
⚠️ L1.4 REFUTED (2026-06-08, the headline correction): the confirming-red-team "confirmation" below was a CODE-READING FALSE POSITIVE. The TDD regression test (
tests/persistent_recovery_watermark_seed_l14.rs, a BARE BatchIncrement that avoids the SET-masks-delta self-cancel) shows BOTH recovery ctors (open_with_recovery_configbyte +recover_from_archiveschar) apply the delta EXACTLY ONCE across recovery→checkpoint→reopen even withwatermark()==0. Root cause the hypothesis missed:open_with_recovery_configreturns the apply-loop trie directly (mmap_ctor.rs:1029 — no re-open, no FIX-C seed), but the post-recoverycheckpoint()captures every recovered record into the image at a HIGHER reconcile GENERATION, so the older archived segment loses the LWW reconcile on reopen → no re-drain, no double-apply. (FIX-C is needed for the open_inner CONVERSION path because its committed tail is an un-checkpointed rotated segment; the recovery path's records are fully checkpoint-subsumed.) $\Rightarrow$ DROP L1.4 (no watermark seed). The GREEN test is retained as the regression guard that the property holds across the L1 applier-redirect. Binding conditions reduce to R2 + R1 (below).(SUPERSEDED) Confirming red-team (2026-06-08) — claimed L1.4 gap real: the watermark base-seed (
max_lsn_in_segments(archive+active)) exists ONLY inopen_inner(the normal-reopen path, byte mmap_ctor.rs:486-514 "F7 FIX C"). The corruption/archive-rebuild ctoropen_with_recovery_config(:852-1038) has NO such seed → post-recoverywatermark()==0→ the checkpoint→reopen BatchIncrement double-apply hole is REAL (and pre-existing/latent — the owned-then-reestablish path also leaves watermark=0). The L1.4 seedmax_lsn_in_segments(collect_retained_wal_segments_for_rebuild(...))spans the FULL drained range (collect_retained… renames the active into archive_dir, recovery.rs:1433, so its segment set = renamed-active + archives), exactly mirroring the proven FIX-C template at open_inner:507-514. $\Rightarrow$ binding condition #2 (L1.4) is validated; implement L1 by hand. Source: Plan-agent design+red-team pass. Carries the L0.2 lesson (verify everyroute_overlay()regime assumption). Plan:slice3-level3-converged-plan-2026-06-08.mdL1 section (lines 100-116). Retrospective that motivated the rigor:slice3-l02-rollback-2026-06-08.md.
The corruption/archive-rebuild ctors install the overlay FIRST, then replay (the INVERSE of
normal reopen). Trace (byte, char identical): open_with_recovery_config →
create(path) (mmap_ctor.rs:914) → apply_create_flip (:172/:276) → flip_to_overlay
(flip.rs:542) → enable_lockfree sets lockfree_root=Some(EMPTY) + stamps Overlay regime —
THEN the apply loop runs (:935-988). So route_overlay()==true with an empty overlay
installed at the apply loop. overlay_eligible_v()==true for ALL V (byte
overlay_write_mode.rs:487, char :131). The redirect target apply_recovered_operation_overlay
(flip.rs:1031) early-returns only when lockfree_root==None — unreachable here. $\Rightarrow$ redirecting
the apply closure is regime-correct as-is.
Keep the existing reconcile/streaming structure (rebuild_from_wal_segments_regime_aware for
the Overlay arm; the inline streaming loop for the Owned arm); change ONLY the per-op sink
apply_*_recovered_operation_no_wal (owned) → apply_recovered_operation_overlay (overlay,
&self). Swapping to drain_segments_into_overlay (flip.rs:1281) would CHANGE tx-filter
behavior (it adds per-segment RecoveryManager tx-resolution the corruption path does not do
today) — see R4. Do NOT do that.
open_with_recovery_config (src/persistent_artrie/mmap_ctor.rs:852-1038):
apply_recovered_operation_no_wal(op) →
<Self as LockFreeOverlay<ByteKey,V,MmapDiskManager>>::apply_recovered_operation_overlay(&trie, op).open_with_recovery_config (src/persistent_artrie_char/mmap_ctor.rs:1076-1362):
*_impl_no_wal —
REWRITE it to for op in recovered_operations_from_record(lsn, record) { let _ = <Self as LockFreeOverlay<…>>::apply_recovered_operation_overlay(&trie, op); }
(recovered_operations_from_record is pub, recovery.rs:353). Preserve
terms_recovered/records_replayed counts. (DRYs byte/char; routes Batch* through the
shared mapper.)recover_from_archives (mmap_ctor.rs:1525-1608): :1567 swap; DELETE
reestablish (:1591-1595). (No Owned inline arm — always rebuild_from_wal_segments_regime_aware.)open_with_full_recovery (mmap_ctor.rs:1397): NO EDIT — delegates to
open_with_recovery_config (:1445). The plan's :1403 edit-site is a false positive.open_with_legacy_loader/open_with_f5_loader(false) off owned replay_records_lww+reestablish
(re-point both-loaders/owned-to-overlay suites to production reopen + a BTreeMap oracle, OR
rewrite the legacy arm to overlay-built correspondence); DELETE the now-dead open_inner/io_uring
LEGACY arms (byte mmap_ctor.rs:675-747 + io_uring_ctor.rs; char mmap_ctor.rs:579-646 +
open_with_depth:935 + io_uring_ctor.rs:349); DELETE replay_records_lww (byte
mutation_core.rs:493, char :263), apply_recovered_operation_no_wal (byte mutation_core.rs:565),
apply_core_recovered_operation_no_wal (char :303), recompute_recovered_increment (byte :679),
value_from_recovered_i64 (char :410). KEEP *_impl_no_wal staging mutators (die at L2/L3).
UNSAFE inventory 0 delta (none of the 4 deleted fns has an unsafe block; rows 23-24 are in
the KEPT *_impl_no_wal via types.rs). Re-run verify-unsafe-boundary-inventory.sh, expect 0.CommittedWatermark::new(0); overlay no-WAL publishers do NOT
advance the watermark (flip.rs:323). So post-redirect the trie has a full overlay but
watermark()==0 → a subsequent checkpoint() records checkpoint_lsn=0, the surviving
archives re-drain on next reopen → BatchIncrement DELTA double-apply (FIX-C class, byte
mmap_ctor.rs:483-494). FIX: after the drain, before return, in each redirected ctor:
let max = AsyncWalWriter::max_lsn_in_segments(&segments).unwrap_or(0); if max>0 { trie.committed_watermark.mark_committed(max); } (mark_committed monotone+idempotent,
committed_watermark.rs:73-90; max_lsn_in_segments pub, async_writer.rs:780). Use the SAME
segments already collected (byte :889 / char :1112 / char-archives :1540). Plausibly also a
PRE-EXISTING latent bug (owned path also leaves watermark=0).reestablish_overlay_from_owned (flip.rs:946) after redirect
builds an EMPTY overlay root from the (now-empty) owned tree and root_ptr.store(empty)
(flip.rs:960) → 100% silent loss of the recovered trie. The applier-swap and reestablish-delete
are ONE atomic unit per ctor — NEVER separate.eligible_v()==true + USE_F5_REOPEN_LOADER==true (flip.rs:800) make the LEGACY arm
unreachable. STALE comments ("ineligible V stays owned", mmap_ctor.rs:580) imply a live path.
Mitigation: L1.3 commit must cite both ==true facts, migrate the oracle atomically, and add a
guard/note so a future eligible_v change can't silently resurrect a broken owned applier.\times$ rotated-archive $\times$
u64 BatchIncrement deltas).(generation,lsn) identical; char inline-match rewrite guarded by
recovery_replay_completeness_correspondence.rs:241.\ne$ None at every apply). 2. tx-filter parity (no new filtering —
applier-swap not drain-swap). 3. Watermark coverage ($\forall$ visible LSN ℓ: ℓ$\le$watermark() after the
seed — #41 invariant; the _Unsafe.cfg must still exhibit loss when the seed is omitted). 4.
No-relog (0 WAL records appended). + a Rust regression test: corruption-rebuild/recover_from_archives
with a BatchIncrement delta → checkpoint() → drop → reopen → counter NOT double-applied (does not
exist today; guards R3/L1.4).max_lsn_in_segments spans archive+renamed-active (not one segment) for the multi-segment
rotated case, and that the new checkpoint→reopen regression test actually FAILS without L1.4. Keep
route_overlay() computed (untouched). NO unsafe prune at L1 (0 delta).The authoritative bug statement is the FIX-C comment at byte mmap_ctor.rs:483-496: checkpoint_lsn=0 < tail_max ⇒ the archive re-drain skip tail_lsn <= checkpoint_lsn is FALSE ⇒ archived records re-drain
⇒ a BatchIncrement DELTA double-applies. Pitfall: a naive archive of [BatchInsert(SET 1), BatchIncrement(+4)] does NOT expose it on a full (ckpt_lsn=0) re-drain — the re-drained leading SET
resets the counter, MASKING the delta (1+4=5 either way). The genuine repro is the FIX-C scenario: the
committed tail (the delta) lives in an ARCHIVED segment, the checkpoint IMAGE already reflects it, and
the reopen re-drains ONLY that tail on top of the image (no masking SET in the re-drained range) →
image+delta = double. So the regression test must mirror the existing post-conversion/rotated-archive
reconcile tests (study reconcile_lww_with_regime + the FIX-C/normal-reopen path), NOT a from-scratch
[SET,delta] archive. Verify it is RED on the current recovery ctor (no seed) and GREEN after L1.4.
Cross-check against the open_inner FIX-C path which is already correct (so the test must target
open_with_recovery_config / recover_from_archives specifically).
L1.1 (byte) and L1.2 (char) independent (commit separately or together) — each fused with its L1.4
seed. L1.3 MUST follow both AND be atomic with the legacy-oracle migration. Per-commit gate: full
suite feature-on + --no-default-features + doctests + verify-formal-correspondence.sh exit 0 +
verify-unsafe-boundary-inventory.sh 0-delta + fmt + cross-repo READ-ONLY cargo check (liblevenshtein-rust).
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 |