Skip to content

ADR-0021: true in-place WRITE_MAP (spike) — DRAFT, do not merge - #88

Merged
qdequele merged 5 commits into
mainfrom
qdequele/adr-0021-writemap-in-place
Oct 5, 2026
Merged

qdequele merged 5 commits into
mainfrom
qdequele/adr-0021-writemap-in-place

Conversation

@qdequele

@qdequele qdequele commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

ADR-0021: true in-place WRITE_MAP — DRAFT, do not merge

Opt-in behind the existing WRITE_MAP flag; the default (heap-staged) path is
untouched (both the flag and the brokering backing are required to engage
it). Under WRITE_MAP, dirty pages are written straight into the mapped file at
their freshly-COW'd page numbers — no heap dirty frame, no commit write-back —
as LMDB's MDB_WRITEMAP does.

Why

On the current tree, ADR-0017 spilling already closed the memory/page-cache gap
(ZeroDB's anon memory ≈ LMDB, fewer disk reads). The residual no-sync write gap
is per-operation commit CPU, and the biggest structural piece of it is that
ZeroDB's WRITE_MAP still heap-staged then memcpy'd into the map at commit. A
fair comparison (both engines WRITE_MAP on) put ZeroDB-writemap at only
0.42–0.53× of LMDB-writemap. This PR removes the heap stage + the commit
write-back.

Graviton4 m8gd NVMe — YCSB, cap 2 GB, no-sync (medians of 2)

config A ops/s ÷LMDB ÷LMDB-wm B ops/s ÷LMDB ÷LMDB-wm write p50 (A/B)
LMDB 259k 1.00 0.38 518k 1.00 0.41 6.2 / 6.8 µs
LMDB WRITE_MAP 673k 2.60× 1.00 1,262k 2.44× 1.00 1.2 / 1.4 µs
ZeroDB default 205k 0.79 0.30 361k 0.70 0.29 13.6 / 14.9 µs
ZeroDB WRITE_MAP (in-place, this PR) 409k 1.58× 0.61 821k 1.58× 0.65 4.4 / 4.5 µs

In-place WRITE_MAP makes ZeroDB 1.58× plain LMDB and closes the gap to
LMDB-writemap to 0.61–0.65× (from ~0.44× heap-staged); write p50 drops ~3×
(13.6 → 4.4 µs). The remaining 0.61–0.65× is LMDB-writemap's 1.2 µs commit vs
ZeroDB's 4.4 µs — the other per-commit CPU (free-list save, allocate, meta
encode), a separate effort that also helps the default path. (x86 bench-server
reproduces the shape: 1.19× plain LMDB, 0.65× LMDB-writemap. commit_census:
~4.1× per commit vs pre-spike heap-staged.)

Gate (final tree, commit 0972be9)

clippy -D warnings clean · cargo test --workspace 641/0 · miri -p zerodb-core 201/0 (+ adapter cursor miri 2/0) · fuzz-quick clean ·
crash-test-quick now exercises in-place (2,591 journaled map regions, with a
vacuousness tripwire so a WRITE_MAP crash cycle cannot silently run the heap
path) · loom 9/0 · stress 180s 3/0 incl. a WRITE_MAP in-place writer
(1,089 spilled commits).

What the production pass resolved (spec-review punch-list)

  • B1 broker is unsafe fn end-to-end — no safe code mints &mut [u8] from
    &self; sole sanctioned call in dirty::map_mut (CLAUDE.md unsafe policy
    amended to allow it).
  • B2 + M1 the UnsafeCell miri test backing (M1) caught that per-spill
    re-derivation was insufficient under Stacked Borrows → in-place txns now hold
    no cached whole-map reference and borrow the view lazily, like RoTxn.
  • B3 map-aware crash fault backend; B4 loom-justified (no new atomic/edge)
    • stress + the M1.13 adapter borrow audit (write-up + miri battery).
  • M2 release-mode TXN-62 guard on the brokered path; M3 full battery
    twinned under WRITE_MAP (no test weakened); m1 SPEC TXN-71/§6.1/C5a/TXN-45b
    • REC-20 amended.

Maintainer calls — resolved

  1. ✅ Ratified (CLAUDE.md, Quentin 2026-10-02): the #[allow(clippy::mut_from_ref)]
    on the broker's unsafe fn surface (clippy 1.97 fires it on unsafe fn too;
    each carries the exclusivity contract inline).
  2. ✅ Ratified: Backing::map_dirty_page's declaration-only
    #[allow(unsafe_code)] at its trait-definition site in zerodb-core::env
    (actual map unsafe stays in zerodb-io).

Documented residual risk (inherent, not a blocker)

Real-mmap cross-thread aliasing rests on the documented SAFETY argument +
loom/stress/crash evidence, not a machine check — as for every mmap engine. miri
covers the single-threaded brokered discipline on heap memory. See
docs/adr/0021-writemap-in-place.md. Ready for maintainer review / merge.

(The separately-approved B12 "used-portion COW copy" lever was A/B-flat and is
not in this PR — recorded as a negative result in PERF-GAP B12.)

🤖 Generated with Claude Code

…, no heap staging, no commit write-back

Behind WRITE_MAP only, and only when the backing brokers map slices
(Backing::dirty_in_map — the real WriteMapBacking); the default heap-staged
path (TXN-45a) is byte-identical for every other backing, including the miri
test backing and the fault-injection backend.

- zerodb-io: MmapWritable::slice_mut, the brokered dirty-page &mut (one new
  unsafe block, SAFETY contract stated); WriteMapBacking implements
  Backing::{dirty_in_map, map_dirty_page}.
- zerodb-core: Backing gains the two brokered methods (safe defaults, no new
  unsafe in core); DirtyStore grows a Slot::{Heap,Map} frame representation —
  in-map frames are realized at their final file offset at allocation time
  (COW copy, new tree page, overflow run), views stay tied to &self/&mut self
  (TXN-39/41); commit C2 and spills skip in-map frames; unspill re-tracks in
  place; the general split copies the in-map frame out to a heap scratch
  (LMDB's own WRITEMAP split copy).
- Spilling under in-place WRITE_MAP degenerates to bookkeeping (TXN-68..72
  observable contract unchanged; dirty_spill writemap suite still passes
  unweakened).
- SPEC 04 §6.4: TXN-45b added (in-place realization, abort = don't advance
  the meta, TXN-62 applied at store time as TXN-70 already does for spills);
  C2 table row and §6.3a cross-reference amended.
- New battery crates/zerodb/tests/writemap_in_place.rs: differential vs the
  default mode (splits, runs, put_reserved, cursor ops, nested reads),
  TXN-45b abort semantics incl. reopen + space reuse, put_reserved in-map.
- commit_census example gains a 'writemap' toggle (fair A/B per ADR-0021).

Spike A/B (macOS arm64, NO_SYNC, 20k single-put commits): WRITE_MAP commit
24.0-34.9 us -> 6.3-8.5 us, put 5.6-8.3 us -> 2.2-2.6 us; default mode
unchanged. Gate: fmt/clippy/test (623 passed)/miri (199 passed)/fuzz-quick/
crash-test-quick (214 cycles, 17 writemap sigkill) all green.
Carries the accepted ADR-0021 (true in-place WRITE_MAP) and its spike-review
punch-list onto the spike branch, which was based on main before the ADR landed.
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: abd7728a-4b0b-4b99-acf2-548d5969f570
📥 Commits

Reviewing files that changed from the base of the PR and between 84582e8 and 957ecd6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • CLAUDE.md
  • PROGRESS.md
  • crates/heed-zerodb/Cargo.toml
  • crates/heed-zerodb/src/iterator.rs
  • crates/zerodb-core/Cargo.toml
  • crates/zerodb-core/src/btree.rs
  • crates/zerodb-core/src/dirty.rs
  • crates/zerodb-core/src/env.rs
  • crates/zerodb-core/src/lib.rs
  • crates/zerodb-core/src/rwtxn.rs
  • crates/zerodb-core/tests/writemap_in_place_miri.rs
  • crates/zerodb-io/Cargo.toml
  • crates/zerodb-io/src/fault.rs
  • crates/zerodb-io/src/lib.rs
  • crates/zerodb-io/src/mmap.rs
  • crates/zerodb-io/src/testmap.rs
  • crates/zerodb-oracle/Cargo.toml
  • crates/zerodb-oracle/examples/commit_census.rs
  • crates/zerodb-oracle/src/bin/crash-harness.rs
  • crates/zerodb-oracle/src/crash/image.rs
  • crates/zerodb-oracle/src/crash/mod.rs
  • crates/zerodb-oracle/tests/crash_harness_smoke.rs
  • crates/zerodb/tests/dirty_spill.rs
  • crates/zerodb/tests/nested_fanout.rs
  • crates/zerodb/tests/put_reserved_adversarial.rs
  • crates/zerodb/tests/reader_stress.rs
  • crates/zerodb/tests/writemap_in_place.rs
  • docs/DECISIONS.md
  • docs/SPEC/04-txn-mvcc.md
  • docs/SPEC/06-recovery.md
  • docs/adr/0021-writemap-in-place.md
 ___________________________________________________________________________________________
< Optimism is an occupational hazard of programming; feedback is the treatment. - Kent Beck >
 -------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…in zerodb-core::dirty (ADR-0021 B1, Quentin 2026-10-02)

Adds zerodb-core::dirty to the unsafe allowlist for the WRITE_MAP in-place path
only: calling zerodb-io's unsafe-fn map-slice broker to realize a dirty page in
the writable map at a freshly-COW'd pgno. States the required SAFETY invariants
(TXN-6 single writer, TXN-62 unreferenced target, one live &mut per region tied
to &mut DirtyStore, whole-map &[u8] re-derived per spill) and requires the broker
be an unsafe fn (resolves B1's policy half; the code change to unsafe fn + B2/B3/
B4 remain for the production pass).
…solved

Opt-in behind WRITE_MAP; the default heap-staged path is untouched.

- B1 (soundness): the map-slice broker is an unsafe fn end to end
  (MmapWritable::slice_mut -> Backing::map_dirty_page); the one sanctioned
  unsafe call lives in zerodb-core::dirty::map_mut with the policy's four
  invariants in its SAFETY block (clippy's mut_from_ref fires on unsafe fns
  too, so its allow stays as a documented false-positive suppression).
- B2 + a stronger M1 finding: heap-staged paths re-derive the writer's
  whole-map &[u8] at every spill; miri then showed that under Stacked
  Borrows ANY copy of a stale view - even the field retag on commit(self) -
  is UB at in-place-written locations, so in-map txns hold no cached
  whole-map reference at all and borrow the view lazily per access
  (RwTxn::whole_map), like readers. TXN-71 amended.
- B3: the fault backend forwards the broker and journals brokered regions
  (deduplicated; bytes resolved at every sync seal point and at capture;
  MS_ASYNC seals preserve per-commit versions for the ordered sub-model);
  image cuts open the real writable map for the WRITE_MAP modes; an fd
  data write under WRITE_MAP is a violation (vacuousness tripwire); smoke
  test pins non-vacuity; harness summary reports journaled regions.
- B4: no new loom model needed (justified in the ADR - in-place introduces
  no new atomic/lock-free interaction; existing reader-table/nested/stamp
  models cover the publish edges); 180 s stress gains the
  writemap-in-place churn-writer variant; M1.13 adapter borrow audit
  written up in the ADR plus a miri battery for the lifetime-erased write
  cursor over the in-place realization (heed-zerodb).
- M1: zerodb_io::testmap::TestWriteMap (test-backing feature,
  UnsafeCell<Box<[u8]>>) runs the whole brokered discipline under miri on
  plain heap memory; caught the B2 insufficiency on its first run.
- M2: release-mode typed TXN-62 guard in RwTxn::allocate for in-map mode
  (pgno > committed_last_pg or reclaimed, each page of a run); failure
  errors the txn instead of clobbering committed data through the map.
- M3: abort-after-spill, all three nested fan-outs and the put_reserved
  adversarial battery parameterized over WRITE_MAP (each asserts the mode
  engaged); the crash battery runs in-place via B3.
- m1: SPEC 04 TXN-71 / par.6.1 C5a wording / TXN-45b amended; SPEC 06
  REC-20 gains the in-map journaling amendment.

Gate: fmt, clippy -D warnings, test --workspace (60 bins, 417/0), miri
-p zerodb-core (201/0, incl. the new in-place batteries), miri -p
heed-zerodb erased_cursor (2/0), fuzz-quick (no findings), crash-test-quick
(235 cycles, 0 violations, 2591 in-place regions), loom (9/0, 1136 s),
stress 180 s (3/0, in-place variant 1089 spilling commits vs 2660 reader
double-walks). Perf: commit_census writemap NO_SYNC 20k medians - pre-spike
heap-staged 45.9 us -> hardened in-place 11.3 us (~4x, spike-level win
preserved; spike itself 10.6 us, within noise of hardened).
@qdequele

qdequele commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

Hardening pass complete + Graviton NVMe headline

Production hardening (commit 0972be9) resolves the spike's B1–B4 / M1–M3 / m1 punch-list. Full gate green: clippy -D warnings clean; cargo test --workspace 641/0; miri -p zerodb-core 201/0 (+ adapter cursor miri 2/0); fuzz-quick clean; crash-test-quick now exercises in-place (2,591 journaled map regions, with a vacuousness tripwire so a WRITE_MAP crash cycle can't silently run the heap path); loom 9/0; stress 180s 3/0 incl. a WRITE_MAP in-place writer (1,089 spilled commits). The miri UnsafeCell test backing (M1) caught a real soundness gap — per-spill re-derivation was insufficient under Stacked Borrows, so in-place txns now hold no cached whole-map reference and borrow the view lazily (like RoTxn).

Graviton4 m8gd NVMe, YCSB, cap 2 GB, no-sync (medians of 2)

config A ops/s ÷LMDB ÷LMDB-wm B ops/s ÷LMDB ÷LMDB-wm write p50 (A/B)
LMDB 259k 1.00 0.38 518k 1.00 0.41 6.2 / 6.8 µs
LMDB WRITE_MAP 673k 2.60× 1.00 1,262k 2.44× 1.00 1.2 / 1.4 µs
ZeroDB default 205k 0.79 0.30 361k 0.70 0.29 13.6 / 14.9 µs
ZeroDB WRITE_MAP (in-place) 409k 1.58× 0.61 821k 1.58× 0.65 4.4 / 4.5 µs

In-place WRITE_MAP makes ZeroDB 1.58× plain LMDB and closes the gap to LMDB-writemap to 0.61–0.65× (from ~0.44× heap-staged); write p50 drops ~3× (13.6→4.4µs). The residual to LMDB-writemap is the non-copy per-commit CPU (free-list save, allocate, meta encode) — a separate effort, which also helps the default path.

Two residuals for maintainer ratification (not correctness gaps)

  1. #[allow(clippy::mut_from_ref)] remains at 5 sites — clippy 1.97 fires it on unsafe fn too, so it cannot be dropped; each sits on an unsafe fn whose # Safety block states the exclusivity. B1's substance (no safe &mut-from-&self) is fully met.
  2. Backing::map_dirty_page's declaration-only #[allow(unsafe_code)] is in env.rs (the trait's home), a hair outside the literal zerodb-core::dirty sanction.

Still a draft / do-not-merge pending maintainer review of those two + the honest residual risks in docs/adr/0021-writemap-in-place.md (real-mmap cross-thread aliasing remains argument+loom/stress/crash, not a machine check, as for every mmap engine).

🤖 Generated with Claude Code

…ration in zerodb-core::env + the clippy::mut_from_ref allows (Quentin 2026-10-02)

Widens the WRITE_MAP in-place sanction to cover the Backing::map_dirty_page
unsafe-fn declaration at its trait-definition site (zerodb-core::env;
declaration-only allow(unsafe_code), trivially-safe default body, actual map
unsafe stays in zerodb-io) and accepts the clippy::mut_from_ref allows on the
broker's unsafe-fn surface (clippy fires on unsafe fn too; contracts inline).
@qdequele
qdequele marked this pull request as ready for review October 5, 2026 08:54
@qdequele
qdequele merged commit 8b066a6 into main Oct 5, 2026
10 checks passed
qdequele added a commit that referenced this pull request Oct 5, 2026
testmap.rs (Linux-only, so missed by the macOS clippy run) and writemap_in_place.rs arrived with #88; the 1.98 MSRV enables manual_is_multiple_of there too.
qdequele added a commit that referenced this pull request Oct 5, 2026
* Bump MSRV to 1.98, CI actions to latest, refresh lockfiles

- MSRV 1.80 -> 1.98 (workspace, heed-shim, fuzz): the toolchain Meilisearch pins in its rust-toolchain.toml. A minor-release item under ADR-0013 rule 6; recorded in CHANGELOG.
- The higher MSRV unlocks clippy lints the old one suppressed (manual_is_multiple_of, unnecessary_map_or -> is_none_or, chunks_exact_to_as_chunks); fixed across the workspace. The two PIL decoders now use as_chunks::<8>() and drop their try_into().expect().
- GitHub Actions: checkout v4 -> v7.0.1, upload-artifact v4 -> v7.0.1, download-artifact v4 -> v8.0.1, dtolnay/rust-toolchain master @ 2026-10-01; rust-cache already at v2.9.2. All still SHA-pinned.
- cargo update on all three lockfiles (semver-compatible only). Every direct dependency was already on its latest major; heed / lmdb-master-sys / heed-traits / heed-types stay at the oracle pins.

* Fix is_multiple_of lints in code merged from main

testmap.rs (Linux-only, so missed by the macOS clippy run) and writemap_in_place.rs arrived with #88; the 1.98 MSRV enables manual_is_multiple_of there too.
qdequele added a commit that referenced this pull request Oct 5, 2026
…ught up to date (#91)

* docs: sweep stale content after #88/#89/#90

Docs only, no code changes. Checked against main at d155fe6.

- PERF-GAP-VS-LMDB: item statuses and the roadmap now match what
  landed (in-place WRITE_MAP, meta free-list annex, spilling,
  validation cache, forced inlining) and what was parked (lazy
  validation, O_DSYNC meta write). Drifted line refs are replaced
  with function names. The 1.8x commit figure is relabelled as the
  macOS run; on Linux, durable commits are at parity.
- BENCH-MAP: benchmark cross-references updated after the
  delete_range, cursor and annex changes.
- PLAN: Phase 3 status table; the 2.8, 3.1, 3.4 and 3.7 notes
  updated.
- DECISIONS and ADR headers: implementation notes only, no decision
  changed. 0019's implementation was parked in PR #86. 0021 and 0022
  merged as #88 and #89.
- DIVERGENCES: D-004 no longer claims DUPSORT was implemented.
  D-014 and D-022 factual notes fixed. No status or approval changed.
- CHANGELOG [Unreleased]: format v2 is a breaking change (v1 files
  are refused at open, migrate with dump then load), plus in-place
  WRITE_MAP, the annex and NO_READ_AHEAD. Notes that the v0.1.0 tag
  was never pushed.
- README, COMPATIBILITY, TOOLS, CONSUMER-GATE, CONTRIBUTING,
  UPSTREAM-BUGS: format v2, the new options, release state, the CI
  description, mimalloc, and the memory behaviour of load and check.
- SPEC: non-normative cross-references only.
- ci.yml: header comment only.
- PROGRESS: one appended line covering #88, #89, #90 and this sweep.

* spec: bring SPEC 00–06 up to date with the engine as it evolved

The maintainer authorized amending normative SPEC text to describe the engine
as it is now. Only deliberate changes are folded in: accepted ADRs, approved
divergences, and changes merged and kept. No code/spec disagreement turned out
to be a correctness bug. All 160 rule IDs (TXN/GC/REC/BT/INV) are kept, none
renumbered or retired. Each file carries a "Revised 2026-10-05" note.

- 02 pages: FORMAT_VERSION 2 and v1 refused at open (ADR-0022), plus the
  annex offset constant. non_free_pages_size uses the GC-23 definition. The
  checksum field is reserved and written as 0. DUPSORT layout is parked.
- 01 flags: NO_READ_AHEAD landed. WRITE_MAP is now in place (ADR-0021).
  fdatasync after msync runs on every platform. The 2.8a pins that were
  pending are adopted as spec text, with DUPSORT itself parked.
- 00 API: WRITE_MAP in-place note. The rest of the surface re-verified, with
  no change needed.
- 03 btree: point get through find_exact. The integer fast path is exactly
  memcmp order. Where dirty bytes live (heap staging, in-place WRITE_MAP,
  spill/unspill). Cursor-path retention covers deletes only. put_reserved
  uses a single descent. Allocation order now includes the annex. Same-size
  overwrite is scoped to inline values: the large-value same-size case was
  never built, tracked in #6. DUPSORT is marked parked.
- 04 txn: snapshot fields include the annex. Frame pool realization note.
- 05 gc: annex section marked ratified (PR #89). Drain representation note.
- 06 recovery: format v2 at REC-1, v2 CRC offsets at REC-8 and REC-22.
  REC-12 states the shipped whole-map msync plus fdatasync, a superset of the
  ranged msync, which stays planned in #45; C3 then C4 then C5 order
  verified. REC-7 notes the parked O_DSYNC meta write.

Also in PERF-GAP: the used-portion COW copy experiment was measured flat and
reverted on 2026-10-02. Its record lived only in 279ceba on an unmerged
branch.

* Prepare the repo for public readers

- Root: CLAUDE.md becomes AGENTS.md, rewritten as a public guide for human and
  AI contributors: project rules, unsafe policy, checks, repo map, style.
  Agent model names, milestone process and personal ratification notes are
  gone. PLAN.md, PROGRESS.md and .claude/ (agent definitions, slash commands)
  are removed from the tree; git history keeps them. /CLAUDE.md and /.claude/
  are gitignored so local assistant configuration stays local.
- Code comments: internal shorthand replaced with plain words in about 200
  files: milestone codes, perf-inventory codes, "Phase N" roadmap labels,
  divergence IDs, and references to the removed files. Spec rule IDs
  (TXN-41, GC-16, ...) and ADR numbers are kept; they point to public docs.
  Every changed .rs line is a comment, except three user-visible strings
  cleaned the same way: the zerodb-tools usage text, the MDB_NOSUBDIR error,
  and the compacting-copy comparator error, which also lost a run of stray
  spaces.
- Approval records: names and chat quotes become "maintainer, <date>" in
  DIVERGENCES, DECISIONS, ADRs, SPEC and code. Decisions and dates kept.
- Docs: CONTRIBUTING points to AGENTS.md. References to removed files are
  rewritten; in historical records (ADRs, bench reports) they are plain text.
  SECURITY: write-transaction memory is bounded by spilling now, except a
  single large value.

Checks (Rust 1.99, macOS aarch64): cargo fmt --check clean. cargo clippy
--workspace --all-targets -D warnings clean, and the same for the
x86_64-unknown-linux-gnu target on the engine crates. cargo test --workspace:
653 passed, 0 failed. cargo doc: the same 37 pre-existing warnings as main,
none new.

* Cut history, process notes and restatements from comments and docs

Comments (about 140 files; comment lines 15,047 → 14,738): removed dated
history ("since 2026-07-21", "amended …", "pre-fix"), review and process
artifacts (review finding IDs, coverage-pass notes, "do not weaken
(AGENTS.md rule 2)" boilerplate), bug-discovery stories (each regression test
keeps one line on what it guards), and long verbatim mdb.c / lmdb.h quotes
(now one sentence plus the reference). Kept every SAFETY comment and atomic
Ordering justification, every invariant and reason a decision was made,
LMDB-parity facts, spec rule IDs, ADR numbers and complete public API docs.

Comments that contradicted the code are corrected:
- heed-zerodb `Database::put_reserved` # Errors: a failing closure returns
  Io and keeps the entry; it does not return Encoding.
- heed-zerodb txn module doc and heed_suite: RwTxn is Send (the writer lock
  is thread-agnostic, TXN-6); they described an old !Send design.
- dirty.rs SPARE_CAP: ZeroDB does spill (TXN-68). meta.rs: the CRC covers
  [0,172) plus the annex ids. lib.rs and page/mod.rs: page::raw is not the
  only unsafe module.
- Three doc comments were attached to the wrong item and are moved. One dead
  intra-doc link is removed. The oracle gc_churn band/page size and the
  multi_db coverage list are fixed, along with a few other stale harness
  descriptions.

Only comments changed in .rs files (checked mechanically; two trailing
comments after an unchanged `},`), plus one fix:
examples/decode_artifact.rs now splits off the engine-mode byte the way the
diff_ops fuzz target does, and prints the mode. It used to decode the mode
byte as an op and print a shifted sequence.

Docs:
- PERF-GAP-VS-LMDB.md goes from 1,160 to 331 lines. It now shows where ZeroDB
  stands per area, which technique closed each gap, what was tried and
  dropped, and what remains with issue links. Every number cites its report
  in benches/results. A lookup table maps the old item codes still cited by
  ADRs, SPEC and the perf ledger.
- BENCH-MAP.md goes from 315 to 270 lines: the rung map is kept, history
  removed.
- DECISIONS.md and DIVERGENCES.md: index rows cut to one short line each. All
  22 divergences are kept, with no status or approval changed.
- benches/results: nothing deleted; every report is either the latest of its
  kind or referenced.

Checks (Rust 1.99): fmt clean. clippy -D warnings clean on macOS and on the
x86_64-unknown-linux-gnu engine crates. cargo test --workspace: 653 passed,
0 failed. cargo doc: same 37 pre-existing warnings as main. No broken
relative links in any Markdown file.

* Address review: unreleased 0.1.0 notes, WRITE_MAP durability row

- CHANGELOG [0.1.0]: say plainly that it was never released. Drop the claims
  that crates were published and binaries attached, drop the tag from the
  patch snippet, and replace the links to the missing v0.1.0 tag. The
  `## [0.1.0]` heading stays, since the release workflow matches it.
- SPEC 01 Table 1, MDB_WRITEMAP: commit flushes the whole map with msync, and
  a synchronous flush also fdatasyncs on every platform (REC-12). This row
  now matches §S7 and the landed-flags table.
qdequele added a commit that referenced this pull request Oct 5, 2026
* docs: sweep stale content after #88/#89/#90

Docs only, no code changes. Checked against main at d155fe6.

- PERF-GAP-VS-LMDB: item statuses and the roadmap now match what
  landed (in-place WRITE_MAP, meta free-list annex, spilling,
  validation cache, forced inlining) and what was parked (lazy
  validation, O_DSYNC meta write). Drifted line refs are replaced
  with function names. The 1.8x commit figure is relabelled as the
  macOS run; on Linux, durable commits are at parity.
- BENCH-MAP: benchmark cross-references updated after the
  delete_range, cursor and annex changes.
- PLAN: Phase 3 status table; the 2.8, 3.1, 3.4 and 3.7 notes
  updated.
- DECISIONS and ADR headers: implementation notes only, no decision
  changed. 0019's implementation was parked in PR #86. 0021 and 0022
  merged as #88 and #89.
- DIVERGENCES: D-004 no longer claims DUPSORT was implemented.
  D-014 and D-022 factual notes fixed. No status or approval changed.
- CHANGELOG [Unreleased]: format v2 is a breaking change (v1 files
  are refused at open, migrate with dump then load), plus in-place
  WRITE_MAP, the annex and NO_READ_AHEAD. Notes that the v0.1.0 tag
  was never pushed.
- README, COMPATIBILITY, TOOLS, CONSUMER-GATE, CONTRIBUTING,
  UPSTREAM-BUGS: format v2, the new options, release state, the CI
  description, mimalloc, and the memory behaviour of load and check.
- SPEC: non-normative cross-references only.
- ci.yml: header comment only.
- PROGRESS: one appended line covering #88, #89, #90 and this sweep.

* spec: bring SPEC 00–06 up to date with the engine as it evolved

The maintainer authorized amending normative SPEC text to describe the engine
as it is now. Only deliberate changes are folded in: accepted ADRs, approved
divergences, and changes merged and kept. No code/spec disagreement turned out
to be a correctness bug. All 160 rule IDs (TXN/GC/REC/BT/INV) are kept, none
renumbered or retired. Each file carries a "Revised 2026-10-05" note.

- 02 pages: FORMAT_VERSION 2 and v1 refused at open (ADR-0022), plus the
  annex offset constant. non_free_pages_size uses the GC-23 definition. The
  checksum field is reserved and written as 0. DUPSORT layout is parked.
- 01 flags: NO_READ_AHEAD landed. WRITE_MAP is now in place (ADR-0021).
  fdatasync after msync runs on every platform. The 2.8a pins that were
  pending are adopted as spec text, with DUPSORT itself parked.
- 00 API: WRITE_MAP in-place note. The rest of the surface re-verified, with
  no change needed.
- 03 btree: point get through find_exact. The integer fast path is exactly
  memcmp order. Where dirty bytes live (heap staging, in-place WRITE_MAP,
  spill/unspill). Cursor-path retention covers deletes only. put_reserved
  uses a single descent. Allocation order now includes the annex. Same-size
  overwrite is scoped to inline values: the large-value same-size case was
  never built, tracked in #6. DUPSORT is marked parked.
- 04 txn: snapshot fields include the annex. Frame pool realization note.
- 05 gc: annex section marked ratified (PR #89). Drain representation note.
- 06 recovery: format v2 at REC-1, v2 CRC offsets at REC-8 and REC-22.
  REC-12 states the shipped whole-map msync plus fdatasync, a superset of the
  ranged msync, which stays planned in #45; C3 then C4 then C5 order
  verified. REC-7 notes the parked O_DSYNC meta write.

Also in PERF-GAP: the used-portion COW copy experiment was measured flat and
reverted on 2026-10-02. Its record lived only in 279ceba on an unmerged
branch.

* Prepare the repo for public readers

- Root: CLAUDE.md becomes AGENTS.md, rewritten as a public guide for human and
  AI contributors: project rules, unsafe policy, checks, repo map, style.
  Agent model names, milestone process and personal ratification notes are
  gone. PLAN.md, PROGRESS.md and .claude/ (agent definitions, slash commands)
  are removed from the tree; git history keeps them. /CLAUDE.md and /.claude/
  are gitignored so local assistant configuration stays local.
- Code comments: internal shorthand replaced with plain words in about 200
  files: milestone codes, perf-inventory codes, "Phase N" roadmap labels,
  divergence IDs, and references to the removed files. Spec rule IDs
  (TXN-41, GC-16, ...) and ADR numbers are kept; they point to public docs.
  Every changed .rs line is a comment, except three user-visible strings
  cleaned the same way: the zerodb-tools usage text, the MDB_NOSUBDIR error,
  and the compacting-copy comparator error, which also lost a run of stray
  spaces.
- Approval records: names and chat quotes become "maintainer, <date>" in
  DIVERGENCES, DECISIONS, ADRs, SPEC and code. Decisions and dates kept.
- Docs: CONTRIBUTING points to AGENTS.md. References to removed files are
  rewritten; in historical records (ADRs, bench reports) they are plain text.
  SECURITY: write-transaction memory is bounded by spilling now, except a
  single large value.

Checks (Rust 1.99, macOS aarch64): cargo fmt --check clean. cargo clippy
--workspace --all-targets -D warnings clean, and the same for the
x86_64-unknown-linux-gnu target on the engine crates. cargo test --workspace:
653 passed, 0 failed. cargo doc: the same 37 pre-existing warnings as main,
none new.

* Cut history, process notes and restatements from comments and docs

Comments (about 140 files; comment lines 15,047 → 14,738): removed dated
history ("since 2026-07-21", "amended …", "pre-fix"), review and process
artifacts (review finding IDs, coverage-pass notes, "do not weaken
(AGENTS.md rule 2)" boilerplate), bug-discovery stories (each regression test
keeps one line on what it guards), and long verbatim mdb.c / lmdb.h quotes
(now one sentence plus the reference). Kept every SAFETY comment and atomic
Ordering justification, every invariant and reason a decision was made,
LMDB-parity facts, spec rule IDs, ADR numbers and complete public API docs.

Comments that contradicted the code are corrected:
- heed-zerodb `Database::put_reserved` # Errors: a failing closure returns
  Io and keeps the entry; it does not return Encoding.
- heed-zerodb txn module doc and heed_suite: RwTxn is Send (the writer lock
  is thread-agnostic, TXN-6); they described an old !Send design.
- dirty.rs SPARE_CAP: ZeroDB does spill (TXN-68). meta.rs: the CRC covers
  [0,172) plus the annex ids. lib.rs and page/mod.rs: page::raw is not the
  only unsafe module.
- Three doc comments were attached to the wrong item and are moved. One dead
  intra-doc link is removed. The oracle gc_churn band/page size and the
  multi_db coverage list are fixed, along with a few other stale harness
  descriptions.

Only comments changed in .rs files (checked mechanically; two trailing
comments after an unchanged `},`), plus one fix:
examples/decode_artifact.rs now splits off the engine-mode byte the way the
diff_ops fuzz target does, and prints the mode. It used to decode the mode
byte as an op and print a shifted sequence.

Docs:
- PERF-GAP-VS-LMDB.md goes from 1,160 to 331 lines. It now shows where ZeroDB
  stands per area, which technique closed each gap, what was tried and
  dropped, and what remains with issue links. Every number cites its report
  in benches/results. A lookup table maps the old item codes still cited by
  ADRs, SPEC and the perf ledger.
- BENCH-MAP.md goes from 315 to 270 lines: the rung map is kept, history
  removed.
- DECISIONS.md and DIVERGENCES.md: index rows cut to one short line each. All
  22 divergences are kept, with no status or approval changed.
- benches/results: nothing deleted; every report is either the latest of its
  kind or referenced.

Checks (Rust 1.99): fmt clean. clippy -D warnings clean on macOS and on the
x86_64-unknown-linux-gnu engine crates. cargo test --workspace: 653 passed,
0 failed. cargo doc: same 37 pre-existing warnings as main. No broken
relative links in any Markdown file.

* Address review: unreleased 0.1.0 notes, WRITE_MAP durability row

- CHANGELOG [0.1.0]: say plainly that it was never released. Drop the claims
  that crates were published and binaries attached, drop the tag from the
  patch snippet, and replace the links to the missing v0.1.0 tag. The
  `## [0.1.0]` heading stays, since the release workflow matches it.
- SPEC 01 Table 1, MDB_WRITEMAP: commit flushes the whole map with msync, and
  a synchronous flush also fdatasyncs on every platform (REC-12). This row
  now matches §S7 and the landed-flags table.

* Release 0.2.0

- Version 0.2.0 for zerodb-core, zerodb-io, zerodb, zerodb-tools and
  zerodb-oracle, with the exact internal pins updated. Lockfiles refreshed.
  heed-zerodb and heed-shim stay at 0.22.1, the heed line they mirror.
- CHANGELOG [0.2.0] is self-contained, since 0.1.0 was prepared but never
  released: what ZeroDB is, how to install it, features, performance with
  sources, verification (including that the consumer test suites last ran
  2026-09-09), requirements, and known gaps. The never-released [0.1.0]
  section is folded in; [Unreleased] is reopened.
- README install snippet (crates.io and the v0.2.0 tag) and status, TOOLS
  install instructions, SECURITY's unsafe inventory (adds the in-place
  WRITE_MAP path), and a stale "since 0.1.0" in COMPATIBILITY.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant