Files
alkblobs/tasks/engine-sqlite-window.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

7.4 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
engine-sqlite-window sqlite engine-state window family — the durable single-node delete window completed
engine-sqlite
narrow low component implementation
wave-3
engines
sqlite
gc

Description

Implement the engine-state companion seam's window family on the sqlite backend (src/sqlite.rs or its seam module): the EngineWindowState impl per ADR-010 §2 as reduced by ADR-012 §5 — the window family only. The pin clauses and the sweep-lock body are dropped dead machinery for sqlite (ADR-012 §5's table: pin clauses no, sweep-lock clause no — the single-flighter is the in-process lock; a sqlite fleet is a recorded non-option, ADR-010 §3). Nothing of EngineFleetState may exist on this engine.

  • ensure_gc_schema — creates gc_window only (gc_window (key BLOB PRIMARY KEY, visible_after INTEGER); the timestamp encoding — SystemTime ↔ integer, sub-second precision for the test tunings — is a recorded design point). Never gc_pins; the embedder's liveness table is never created here (ADR-008's schema-ownership rule — the sweep reads it and never owns it). Called at store construction by the store core (store-sqlite-construction wires the call); the clause body is engine-side.
  • window_stage — stage candidates into the durable window, idempotent per (key, deadline) (INSERT OR IGNORE semantics — the body's discipline; the store stages each candidate once per sweep, and a re-stage of the same key at a new deadline updates the row). Virgin store: tolerated (the table exists from construction; a no-tables-yet database stages lazily or errors nothing — the Backend trait's engine posture carries here).
  • window_take(now) — take overdue candidates (visible_after <= now): the rows leave the window table and return as keys for the calling sweep to re-arbitrate and delete — the executor is the next sweep (ADR-012 §6.7). Empty when nothing is overdue; virgin store: empty. The take is one atomic step (selected rows removed and returned together — a row is never handed out twice).
  • Contract tests per the applicability row (ADR-012 §5's table is the contract-test matrix): the schema creates the window table only (assert gc_pins does not exist); stage idempotence per (key, deadline) incl. the re-stage-at-new-deadline form; take returns exactly the overdue set, removes it, leaves future rows; empty/virgin shapes; the timestamp encoding's boundary (visible_after == now is overdue — <= per the seam doc).

The store core drives these clauses (store-sweep-durable-window); this task ships the clauses and their engine-level contract tests.

Acceptance Criteria

  • The sqlite backend implements EngineWindowState — the window family only; no pin-clause or sweep-lock body exists anywhere in the sqlite engine
  • ensure_gc_schema creates gc_window only; gc_pins is never created by sqlite (contract-tested)
  • window_stage is idempotent per (key, deadline); a re-stage at a new deadline updates the row
  • window_take returns exactly the overdue set (<= now boundary), removes it atomically, leaves future rows; empty on none/virgin
  • Clause contract tests green; cargo test (default) green; cargo clippy --all-targets -- -D warnings and cargo fmt --check green

References

  • src/gc.rs (EngineWindowState — the seam contract and its clause docs)
  • docs/architecture/decisions/010-backend-io-seams-and-fleet-state.md §2
  • docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §5 (the applicability table; the sqlite reduction), §6.7 (the executor)
  • docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2 (the durable window's semantics)
  • docs/architecture/decisions/005-pooled-cas-and-gc-mechanism.md (the delete-window protocol)

Notes

  • 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 — nothing of EngineFleetState is implementable or referenced on this engine (ADR-012 §5's sqlite row: the single-flighter is the in-process sweep lease on GcHome, a sqlite fleet is a recorded non-option).
  • Timestamp encoding (recorded design point): visible_after travels as a signed i64 nanosecond count from the Unix epoch — sub-second precision preserved for the test tunings, negatives for pre-epoch instants, full i64 range. Helpers time_to_nanos / nanos_to_time sit beside size_u64 in src/sqlite.rs.
  • Staging discipline: one prepare_cached upsert per row — INSERT … ON CONFLICT(key) DO UPDATE SET visible_after = excluded.visible_after. The row's primary key is the window candidate's key, so a same-deadline re-stage is idempotent (one row, unchanged value) and a new-deadline re-stage updates the row rather than duplicating it. INSERT OR IGNORE alone would have made the new-deadline update a no-op, so the upsert carries both clauses of the idempotence contract.
  • Take atomicity: DELETE FROM gc_window WHERE visible_after <= ? RETURNING key — one statement on the single pooled connection, so selection and removal are one atomic step (a row is never handed out twice); RETURNING order is unspecified, so the returned keys are sorted for determinism.
  • Virgin-store tolerance split per the sqlite engine's recorded posture: window_take is a read — a no-tables-yet database maps to empty via the existing is_no_such_table tolerance; window_stage is a write — a tableless database surfaces the engine error rather than silently creating schema (the constructor-vs-lazy design point: store construction always wires ensure_gc_schema, so the table exists whenever the engine is in store service; the lazily staged option was rejected as contradicting that recorded point).
  • Schema timing unchanged from the pool table's recorded design point: the backend constructor never creates gc_window itself — the store construction call (store-sqlite-construction) wires ensure_gc_schema, which is idempotent and creates gc_window only. The clause-level tests use a new_window_backend() fixture that mirrors that wiring.
  • The boundary contract (visible_after <= now, inclusive) is contract-tested, including the nanosecond slack row (visible at now + 1ns stays).

Summary

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, contract-tested through sqlite_master), window_stage (key-keyed upsert; idempotent per (key, deadline), new-deadline re-stage updates the row), and window_take (DELETE … RETURNING — one atomic overdue take with the <= now boundary, future rows left in place). Signed-nano timestamp encoding recorded; virgin-store tolerance split read/write per the sqlite engine's posture. Six clause contract tests added (schema window-only, staging idempotence + deadline update, overdue-exact take + future rows left, the <= boundary with nanosecond slack, and both virgin shapes). Verification: cargo test green (58 lib + 5 integration), cargo clippy --all-targets -- -D warnings green, cargo fmt --check green.