test: delivery-invariant harness (model + concurrency + lifecycle) - #98
test: delivery-invariant harness (model + concurrency + lifecycle)#98WiktorStarczewski wants to merge 3 commits into
Conversation
…pede); harden invariant harness per review
Review (internal + Codex) — findings appliedTwo independent reviews. The harness did its job on day one: it surfaced a real production availability bug. Production bug found & fixed (both reviews, HIGH/CRITICAL)The file-backed concurrent test needed a warm-up because, without it, ~16 pool connections race to run migration DDL on a fresh volume ("disk I/O error"). That's not a test artifact: connections are created lazily and each runs migrations on creation, and A "CRITICAL" Codex finding — rejected as empirically falseCodex claimed the model's stranded-reset over-fires on an empty DB (arguing Applied (both reviewers)
Not changed (both agreed / verified correct): Verification after fixes: 28/28 tests pass (~6s default; 1500–2000-iter sweeps green); |
Why
Three separate "notes not delivered" incidents — the
created_attimestamp-collision race, the:memory:pool-isolation bug, and a cursor stranded above a regressedseqhigh-water — were all the same invariant violated three ways:Every one was found in production/stress, not by a unit test, because example-based tests only cover the cases the author imagined. This PR adds a harness that explores the state space so a fresh bug in this class surfaces as a replayable failing seed.
What
crates/node/src/database/invariant_tests.rs(in-crate#[cfg(test)], zero new dependencies — seededrand+ a hand-rolled greedy shrinker + an RAII temp-file helper):Databaseover random op sequences (store / fetch-with-cursor / drain / recreate). On failure it prints the seed and the greedily-minimized failing sequence.:memory:pool, guarding the pool-size=1 clamp); a final drain must deliver every note exactly once.cleanup_old_notesretention + high-water preservation, and cross-batch pagination.6 new tests; CI-fast by default (
finished in ~1.5s); deep soak viaNTS_INV_ITERS/NTS_INV_LEN/NTS_INV_CONC_ITERS; reproduce viaNTS_INV_SEED. Documented under Developer Guide → Testing.Validation notes
sqlite_sequence.seqfornotesis0(not absent), so the backend correctly resets anycursor > 0on an empty DB. The correct model and backend agree on this.Verification
cargo test -p miden-note-transport-node— 27/27 pass (21 existing + 6 new).clippy --locked --all-targets --workspace -D warnings— clean.fmt --check— clean.