Reviewed the wave-3 commits (engine-sqlite, engine-sqlite-window, store-sqlite-construction, store-sweep-durable-window, suite-column-sqlite) against the cited ADR/spec text line by line: ADR-003/007/008 §2, ADR-010 §2, ADR-012 §1/§5/§6.7, store-api.md, implementation.md §Review gates — the engine-vs-contract conformance (suite column green server-less in the default build; the window family contract-tested per its applicability row; virgin-store semantics incl. the no-tables-yet form; the size metadata-only discipline proven index-riding), the durability posture (WAL + synchronous=NORMAL verified at open; the single-writer ceiling posture, not hedge), the durable sweep form vs ADR-008 §2/ADR-012 §6.7 (stage at mark_end + window; next-sweep execution with raced execution-time re-arbitration; schedule-relative exact counts; aborts stage and execute nothing), the seam reduction (gc_window only; no pin rows, no sweep-lock body, no EngineFleetState), and the blocking discipline (all rusqlite in spawn_blocking). Named design points audited as resolved; family conventions clean; no wave-4 amendments arise. Inline fixes (review-of-record): - src/gc.rs: the seam's window_stage doc retired the wave-1 lazy-create hedge for the shipped constructor-at-open posture (a tableless database surfaces the engine error on stage; per-engine tolerances are each engine's recorded posture) - tasks/engine-sqlite-window, store-sweep-durable-window, suite-column-sqlite: stray placeholder lines above the filled Notes/Summary removed (the wave-2 gate's same cleanup) - tests/conformance/README.md: trailing newline added Verification (all re-run green after the fixes): - cargo test (default): 69 lib + 19 conformance + 3 git-interop - cargo test --features mem / --all-features: 124 lib + 54 conformance + 4 git-interop each - cargo clippy --all-targets -- -D warnings (default + all-features) - cargo fmt --check - cargo doc --no-deps at the pre-existing warning baseline (26) Wave 4 (postgres) decomposition is unblocked.
14 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | |||
|---|---|---|---|---|---|---|---|---|---|---|---|
| review-wave-3 | Wave 3 review gate — the sqlite engine vs the contract | completed |
|
narrow | low | phase | review |
|
Description
The wave-3 review gate — the engine-wave review shape (docs/plans/implementation.md §Review gates: "engine-vs-contract conformance"), before wave 4 decomposes. The gate reads the implementation against the pinned ADR text line by line (the wave-1/2 gates' method).
Gate checks:
- Engine-vs-contract conformance: the suite column green
server-less; the engine-state window family contract-tested per its
applicability row (ADR-012 §5's table — window family yes, pin
clauses no, sweep-lock body no); virgin-store semantics including
the no-tables-yet form; the
sizemetadata-only discipline (the indexed column probe never loads the value blob). - The sqlite posture vs ADR-003/007: WAL +
synchronous=NORMALas the shipped durability tier; the single-writer ceiling documented as posture, not hedged (REQ-1's economics); prepared-statement discipline;hasas an EXISTS probe; the B5 row shape (key/value/ size); bounded reads. - The durable-window sweep vs ADR-008 §2 / ADR-012 §5/§6.7:
candidates staged at
visible_after = mark_end + window(the constructor-tunable delay, shipped default 5 min); the executor is the next sweep; execution-time re-arbitration; report counts exact relative to the schedule; the inline form preserved verbatim for non-SQL engines; the single-node posture unchanged (pins/liveness/ arbitration lock in-process — only the window's persistence is engine rows); the one-window-host posture recorded. - The seam reduction honored: no pin rows, no sweep-lock body
anywhere in the sqlite engine (dead machinery per ADR-012 §5);
ensure_gc_schemacreatesgc_windowonly; the embedder's liveness table never created by the engine. - Blocking discipline: all rusqlite work off the async path
(
spawn_blocking); no blocking I/O under internal locks; the connection posture recorded. - Named design points audited as resolved (each recorded in its task's Notes): the connection posture; the timestamp encoding; schema-creation timing vs the no-tables-yet tolerance; the kv cursor dispatch shape over multiple kv engines; the protect-consult posture on overdue execution; the delay-0 test tuning's legality.
- Family conventions: no comments in code (doc comments on public
API fine), thiserror, tokio-only async, no unwrap/expect outside
tests, naming, one-module-per-file re-export shape, the
#![allow(dead_code)]scope notes matching their remaining scope. - Gates green:
cargo test(default — the sqlite column runs here),cargo test --features mem,cargo test --all-features,cargo clippy --all-targets -- -D warnings,cargo clippy --all-features --all-targets -- -D warnings,cargo fmt --check.
Findings are fixed inline where cheap, or recorded as wave-4 amendments where they shape the next decomposition. The gate's completion is what unblocks wave 4's decomposition.
Acceptance Criteria
- Every gate check above read and verified against the cited ADR text (not from memory of it)
- Named design points each decided, recorded, and consistent with the specs
- Findings fixed inline or recorded as wave-4 amendments with owners
- All gates re-run green after any fixes
- Wave 4 decomposition unblocked (recorded in this task's Summary)
References
- docs/plans/implementation.md (§Wave 3, §Review gates — engine wave reviews)
- docs/architecture/decisions/003-backend-contract-and-dispatch.md
- docs/architecture/decisions/007-two-kv-engines-sqlite-and-postgres.md
- docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2
- docs/architecture/decisions/010-backend-io-seams-and-fleet-state.md §2
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §1/§5/§6.7
- docs/architecture/store-api.md
- tasks/review-wave-2.md (the gate method)
Notes
Filled by the review agent (2026-10-12). Every gate check was read against the cited ADR/spec text (the files, not memory): ADR-003, ADR-007, ADR-008 §2, ADR-010 §2, ADR-012 §1/§5/§6.7 (plus §2–§4/§6.1– §6.5 where the gate's checks cite them), docs/plans/implementation.md §Review gates, store-api.md, and the gate method from review-wave-2. Findings below; everything else passed.
- Engine-vs-contract conformance — verified. The suite column is
green server-less and runs in the default build (feature
sqlitedefault-on, ADR-007/013 §4; 19 conformance tests, never skips — README §SKIP posture honored). The window family is contract-tested per its ADR-012 §5 applicability row: schema createsgc_windowonly (gc_pinsasserted never created, throughsqlite_master, on constructed and tableless databases alike; the twice-at-open call idempotent), staging idempotence per(key, deadline)incl. the re-stage-at-new-deadline upsert form, take returns exactly the overdue set and removes it atomically, future rows left in place — and nothing ofEngineFleetStateis implementable or implemented on the engine. Virgin-store semantics: all read paths are no-ops against a genuinely tableless database file (has/get/size/list → absent/empty, delete →Missing;window_take→ empty), tested at both engine and facade form; the write-read-only split (stage surfaces the engine error, never silently creates schema) is the recorded constructor-vs-lazy design point. Thesizemetadata-only discipline: the dedicated size column probed viaSELECT size WHERE key = ?, exact for large/absent keys, andEXPLAIN QUERY PLANasserts the probe rides the key's index (USING INDEX) — never a scan or value load. - The sqlite posture vs ADR-003/007 — verified. WAL +
synchronous=NORMALset at openPRAGMA-verified (the constructor probes the mode actually engaged; a:memory:database that cannot hold WAL is a construction error, tested; the pragma posture asserted on the backend's own connection —synchronousis per-connection). The single-writer ceiling is recorded as posture, not hedged (the module doc carries the ~1.2k objects/s POC #5 B3 number beside REQ-1's economics, matching ADR-007's text).prepare_cacheddiscipline throughout (every engine statement);hasis theSELECT EXISTSprobe; the B5 row shapeblobs (key BLOB PRIMARY KEY, value BLOB, size INTEGER NOT NULL); reads bounded (the materializing body holds only kv-tier content; the 64 KiB put-chunk; the staged commit's full publication through the sameINSERT OR IGNOREclause). - The durable-window sweep vs ADR-008 §2 / ADR-012 §5/§6.7 —
verified. Candidates staged at
visible_after = mark_end + windowwith the constructor-tunable delay (DEFAULT_DELETE_WINDOW_DELAY, 5 min pinned and constructor-passable;Duration::ZEROthe legal degenerate test tuning). The executor is the next sweep: the sweep body runsexecute_overdue_window(take-then-re-arbitrate-at- execution-time, batched ~100) before its own mark, exactly §6.7's "before/alongside its own marking". Execution-time re-arbitration: the race-across-the-delay test proves a put landing during the window survives via its pin (pin-before-publish) cancelling the candidate. Report counts exact relative to the schedule:candidates_staged= staged this sweep,deleted/cancelled= the overdue set executed this sweep; the durable abort shapes (NoLivenessSources/ProtectFailed/SweeperLock) delete, execute, and stage nothing (the ProtectFailed row proves the overdue set stays in the window — abort precedeswindow_take). The inline form is preserved verbatim (extracted body; the mem/local wave-2 suites green unchanged). The single-node posture is unchanged (pins/ liveness/arbitration lock in-process; only the window's persistence is engine rows) and the one-window-host posture is recorded in the store module doc + constructor docs (the form branch keys off the kv-engine enum, never a flag; wave-5 pg-lo dormancy slots in). - The seam reduction honored — verified. No pin rows and no
sweep-lock body anywhere in the sqlite engine (dead machinery per
ADR-012 §5 dropped by construction — not stubbed);
ensure_gc_schemacreatesgc_windowonly; the embedder's liveness table is never created by the engine (ADR-008's schema-ownership rule, doc-pinned at the seam and asserted in tests). - Blocking discipline — verified. Every rusqlite operation
(constructor, all seven methods, the staged commit, the window
clauses, the test instruments) routes through the
blockingspawn_blockinghelper; the cursor/staging read bodies are in-memory after materialization and need none. No blocking I/O under internal async locks: the GcHome arbitration lock stays short-held and I/O-free (the marker mechanism), the sqlite connection mutex is short-held and lives insidespawn_blocking. The connection posture (one connection behind a short-heldparking_lot::Mutex, shared with staging handouts viaArc, parking_lot non-poisoning) is recorded. - Named design points audited as resolved — each recorded in its
task's Notes and consistent with the specs: the connection posture
(engine-sqlite Notes + module doc); the timestamp encoding (signed
i64 nanos since epoch, sub-second precision for test tunings,
pre-epoch negatives — boundary-tested); schema-creation timing vs
the no-tables-yet tolerance (constructor
CREATE TABLE IF NOT EXISTS, read-only tolerance, write surfaces the error — engine- tested against a tableless file); the kv cursor dispatch shape (KvCursorsub-enum behindAnyCursor's one kv arm — per-engine variants rejected for copying the materializing arm's consumers; postgres slots one arm in at wave 4); the protect-consult posture on overdue execution (the consult runs once per sweep above the form branch and extends to the executor phase — overdue re-arbitrations carryconsult_protect = false, the inline form's same posture; the ProtectFailed-before-execution test pins it); the delay-0 test tuning's legality (Duration::ZEROthe legal degenerate tuning, execute-on-next-sweep, ADR-008 §2 constructor-tunable reading). - Family conventions — clean. No unwrap/expect/panic outside
#[cfg(test)](audited every occurrence); thiserror family (engine errors surface asError::Ioviadb_err,Missingvia the rows-affected/virgin-store mapping); tokio-only async; naming and one-module-per-file re-export shape hold (DEFAULT_DELETE_WINDOW_DELAYre-exported from lib.rs); the#![allow(dead_code)]scope notes updated to the landed state (backend.rs's kv-put line; gc.rs's window-family-has-callers line; sqlite.rs's cfg-gated scope). - Boundary-wording note (no fix, recorded): ADR-012 §6.7 says
overdue rows are taken "past
visible_after" while the seam's operative contract (src/gc.rs's clause doc, wave-1-pinned and contract-tested) isvisible_after <= now— a row visible exactly atnowis taken. The nanosecond-scale divergence is immaterial (the window delay is minutes; execution-time re-arbitration protects regardless), the seam doc is the crate-internal contract the engine implements, and the ADR's prose is loose where the seam is precise. No change. - Inline fixes applied (review-of-record):
src/gc.rs—EngineWindowState::window_stage's doc still carried the wave-1 hedge ("Virgin store: creates the window lazily or errors nothing"), contradicting the shipped posture's recorded design point (staging surfaces the engine error on a tableless database; the lazy-create option was rejected in engine-sqlite-window's Notes). The clause doc now states the settled posture: the schema runs at store construction (the store-coreensure_gc_schemacall), a tableless database surfaces the error rather than silently creating schema, and per-engine tolerances are each engine's recorded posture.tasks/engine-sqlite-window.md,tasks/store-sweep-durable- window.md,tasks/suite-column-sqlite.md— the stray "> To be filled…" placeholder lines above their already-filled Notes/Summary bodies removed (the wave-2 gate's same cleanup).tests/conformance/README.md— trailing newline added (the wave-3 amendment hunk ended the file mid-line).
- No wave-4 amendments arise from this gate.
Summary
Wave-3 review gate complete: every gate check was read against the
cited ADR/spec text line by line and verified — the sqlite engine's
contract conformance (WAL+NORMAL pragma posture verified at open,
prepare_cached discipline, the EXISTS probe, the B5 row shape, the
indexed size probe proven index-riding via EXPLAIN QUERY PLAN,
CAS first-writer-wins on both put forms, both stage-hygiene forms,
virgin-store reads incl. the no-tables-yet form against a genuinely
tableless file), the window family contract-tested per its ADR-012 §5
applicability row (gc_window only, no pin rows, no sweep-lock body,
no EngineFleetState anywhere), the durable sweep form against
ADR-008 §2/ADR-012 §6.7 (stage at mark_end + window, the next sweep
as executor with execution-time re-arbitration raced and proven,
schedule-relative exact counts, the three abort shapes executing and
staging nothing, the protect-consult posture recorded), the seam
reduction honored, the blocking discipline (all rusqlite in
spawn_blocking, no I/O under internal async locks), the conformance
column green server-less in the default build with the medium oracle
and durable-schedule rows (README amendment recorded), and all named
design points decided/recorded/consistent. Findings were minor and
fixed inline: the stale lazy-create hedge on the seam's
window_stage doc amended to the settled posture, three task-file
placeholder strays removed, README's missing trailing newline. No
wave-4 amendments arise. All gates re-run green after the fixes:
cargo test (69 lib + 19 conformance + 3 git-interop, default),
cargo test --features mem and cargo test --all-features (124 lib +
54 conformance + 4 git-interop each), cargo clippy --all-targets -- -D warnings and --all-features --all-targets green, cargo fmt --check green, cargo doc --no-deps at the pre-existing warning
baseline (26, unchanged). Wave 4 decomposition is unblocked — the
postgres kv engine decomposes against the contract surface as
reviewed.