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

259 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: review-wave-3
name: Wave 3 review gate — the sqlite engine vs the contract
status: completed
depends_on: [suite-column-sqlite]
scope: narrow
risk: low
impact: phase
level: review
tags: [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
- [x] Every gate check above read and verified against the cited ADR
text (not from memory of it)
- [x] Named design points each decided, recorded, and consistent with
the specs
- [x] Findings fixed inline or recorded as wave-4 amendments with
owners
- [x] All gates re-run green after any fixes
- [x] 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.