From 97cdf682c4b1a8813fc75f14d932edc0f8fb46dd Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Mon, 12 Oct 2026 05:22:29 +0000 Subject: [PATCH] =?UTF-8?q?docs(review):=20the=20wave-3=20review=20gate=20?= =?UTF-8?q?=E2=80=94=20every=20gate=20check=20green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/gc.rs | 11 +- tasks/engine-sqlite-window.md | 4 - tasks/review-wave-3.md | 179 ++++++++++++++++++++++++++-- tasks/store-sweep-durable-window.md | 4 - tasks/suite-column-sqlite.md | 4 - tests/conformance/README.md | 2 +- 6 files changed, 180 insertions(+), 24 deletions(-) diff --git a/src/gc.rs b/src/gc.rs index fdfa0f1..eaa2765 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -561,9 +561,14 @@ pub(crate) trait EngineWindowState: Backend { /// Stage candidates into this engine's durable delete window (idempotent /// staging per `(key, deadline)` is the body's discipline; the store - /// stages each candidate once per sweep). Virgin store: creates the - /// window lazily or errors nothing — reads and no-op writes stay - /// no-ops (the Backend trait's engine posture carries here). + /// stages each candidate once per sweep). The window's schema runs at + /// store construction (the store-core [`Self::ensure_gc_schema`] call, + /// the constructor-vs-lazy timing design point), so staging always sees + /// its table in real service — no lazy create. A genuinely tableless + /// database surfaces the engine error on stage rather than silently + /// creating schema; staging tolerance beyond that is each engine's + /// recorded posture (the Backend trait's engine posture carries; + /// sqlite's is recorded in src/sqlite.rs's module doc). async fn window_stage(&self, candidates: &[WindowCandidate]) -> Result<(), Error>; /// Take overdue candidates (`visible_after <= now`): the rows leave diff --git a/tasks/engine-sqlite-window.md b/tasks/engine-sqlite-window.md index 058bc18..7814206 100644 --- a/tasks/engine-sqlite-window.md +++ b/tasks/engine-sqlite-window.md @@ -81,8 +81,6 @@ this task ships the clauses and their engine-level contract tests. ## Notes -> To be filled by implementation agent - - The `EngineWindowState` impl lives in `src/sqlite.rs` after the `Backend` impl, as `impl EngineWindowState for SqliteBackend`. The pin clauses and the sweep-lock body are absent by construction — @@ -128,8 +126,6 @@ this task ships the clauses and their engine-level contract tests. ## Summary -> To be filled on completion - The sqlite engine-state seam's window family landed: `impl EngineWindowState for SqliteBackend` in `src/sqlite.rs` — `ensure_gc_schema` (creates `gc_window` only, never `gc_pins`, diff --git a/tasks/review-wave-3.md b/tasks/review-wave-3.md index c93ed6f..6119c3e 100644 --- a/tasks/review-wave-3.md +++ b/tasks/review-wave-3.md @@ -1,7 +1,7 @@ --- id: review-wave-3 name: Wave 3 review gate — the sqlite engine vs the contract -status: pending +status: completed depends_on: [suite-column-sqlite] scope: narrow risk: low @@ -67,14 +67,14 @@ completion is what unblocks wave 4's decomposition. ## Acceptance Criteria -- [ ] Every gate check above read and verified against the cited ADR +- [x] 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 +- [x] Named design points each decided, recorded, and consistent with the specs -- [ ] Findings fixed inline or recorded as wave-4 amendments with +- [x] 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) +- [x] All gates re-run green after any fixes +- [x] Wave 4 decomposition unblocked (recorded in this task's Summary) ## References @@ -89,8 +89,171 @@ completion is what unblocks wave 4's decomposition. ## Notes -> To be filled by the review agent +> 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 -> To be filled on completion \ No newline at end of file +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. \ No newline at end of file diff --git a/tasks/store-sweep-durable-window.md b/tasks/store-sweep-durable-window.md index 06e296d..c64a457 100644 --- a/tasks/store-sweep-durable-window.md +++ b/tasks/store-sweep-durable-window.md @@ -92,8 +92,6 @@ window, single-node: ## Notes -> To be filled by implementation agent - The durable form's shape as it landed: - **The branch is the kv-engine enum match itself** (`sweep_window`'s @@ -126,8 +124,6 @@ The durable form's shape as it landed: ## Summary -> To be filled on completion - The sweep's durable SQL-backed form landed beside the inline form in `src/store.rs` (the first durable delete window, single-node; ADR-008 §2 staged re-arbitrated delete, ADR-012 §5/§6.7 the-executor-is-the- diff --git a/tasks/suite-column-sqlite.md b/tasks/suite-column-sqlite.md index 31cd8c5..185fd49 100644 --- a/tasks/suite-column-sqlite.md +++ b/tasks/suite-column-sqlite.md @@ -101,8 +101,6 @@ the default build (feature `sqlite` is default-on). ## Notes -> To be filled by implementation agent - The column as it landed (`tests/conformance/sqlite_column.rs`, 17 tests): - **Factories**: `dual-tier sqlite+local` (the default-build @@ -158,8 +156,6 @@ The column as it landed (`tests/conformance/sqlite_column.rs`, 17 tests): ## Summary -> To be filled on completion - The sqlite column — the suite's first SQL-backed column — is green: the default-build production shape (`kv = sqlite` + `large = local`, feature `sqlite` default-on) runs the form-independent reference rows diff --git a/tests/conformance/README.md b/tests/conformance/README.md index 2b9e7bc..6e85aa9 100644 --- a/tests/conformance/README.md +++ b/tests/conformance/README.md @@ -360,4 +360,4 @@ feature-gated on `sqlite` — **default-on**, so the column runs in the default build: every `cargo test` run exercises it. The sqlite engine's no-tables-yet read tolerance is engine-instrumented (src/sqlite.rs's tests; the constructor-vs-lazy timing design point -there), the column's virgin-store row being its facade form. \ No newline at end of file +there), the column's virgin-store row being its facade form.