Files
alkblobs/tasks/review-wave-3.md
T
glm-5.3-flash 97cdf682c4 docs(review): the wave-3 review gate — every gate check green
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.
2026-10-12 05:22:29 +00:00

14 KiB
Raw Blame History

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
suite-column-sqlite
narrow low phase review
wave-3
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 size metadata-only discipline (the indexed column probe never loads the value blob).
  • The sqlite posture vs ADR-003/007: WAL + synchronous=NORMAL as the shipped durability tier; the single-writer ceiling documented as posture, not hedged (REQ-1's economics); prepared-statement discipline; has as 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_schema creates gc_window only; 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 sqlite default-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 creates gc_window only (gc_pins asserted never created, through sqlite_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 of EngineFleetState is 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. The size metadata-only discipline: the dedicated size column probed via SELECT size WHERE key = ?, exact for large/absent keys, and EXPLAIN QUERY PLAN asserts 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=NORMAL set at open PRAGMA-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 — synchronous is 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_cached discipline throughout (every engine statement); has is the SELECT EXISTS probe; the B5 row shape blobs (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 same INSERT OR IGNORE clause).
  • The durable-window sweep vs ADR-008 §2 / ADR-012 §5/§6.7 — verified. Candidates staged at visible_after = mark_end + window with the constructor-tunable delay (DEFAULT_DELETE_WINDOW_DELAY, 5 min pinned and constructor-passable; Duration::ZERO the legal degenerate test tuning). The executor is the next sweep: the sweep body runs execute_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 precedes window_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_schema creates gc_window only; 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 blocking spawn_blocking helper; 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 inside spawn_blocking. The connection posture (one connection behind a short-held parking_lot::Mutex, shared with staging handouts via Arc, 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 (KvCursor sub-enum behind AnyCursor'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 carry consult_protect = false, the inline form's same posture; the ProtectFailed-before-execution test pins it); the delay-0 test tuning's legality (Duration::ZERO the 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 as Error::Io via db_err, Missing via the rows-affected/virgin-store mapping); tokio-only async; naming and one-module-per-file re-export shape hold (DEFAULT_DELETE_WINDOW_DELAY re-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) is visible_after <= now — a row visible exactly at now is 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):
    1. 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-core ensure_gc_schema call), a tableless database surfaces the error rather than silently creating schema, and per-engine tolerances are each engine's recorded posture.
    2. 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).
    3. 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.