- impl EngineWindowState for SqliteBackend, the window family only per ADR-012 §5's sqlite row; no pin-clause or sweep-lock body exists — EngineFleetState is never implemented on this engine - ensure_gc_schema creates gc_window only (never gc_pins; the embedder's liveness table is never created — ADR-008 schema ownership) - window_stage is a key-keyed upsert: idempotent per (key, deadline), a re-stage at a new deadline updates the row - window_take is one atomic DELETE … RETURNING with the <= now boundary; future rows left in place; tableless take is a no-op read, tableless stage surfaces the engine error (the recorded read/write tolerance split) - visible_after encodes as signed i64 nanoseconds from the epoch (recorded design point; sub-second precision for test tunings) - six clause contract tests per the ADR-012 §5 sqlite row Verification: cargo test green (58 lib + 5 integration); cargo clippy --all-targets -- -D warnings green; cargo fmt --check green.
7.5 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 |
|
narrow | low | component | implementation |
|
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— createsgc_windowonly (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). Nevergc_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-constructionwires the call); the clause body is engine-side.window_stage— stage candidates into the durable window, idempotent per(key, deadline)(INSERT OR IGNOREsemantics — 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_pinsdoes 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 == nowis 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_schemacreatesgc_windowonly;gc_pinsis never created by sqlite (contract-tested)window_stageis idempotent per(key, deadline); a re-stage at a new deadline updates the rowwindow_takereturns exactly the overdue set (<= nowboundary), removes it atomically, leaves future rows; empty on none/virgin- Clause contract tests green;
cargo test(default) green;cargo clippy --all-targets -- -D warningsandcargo fmt --checkgreen
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
To be filled by implementation agent
- The
EngineWindowStateimpl lives insrc/sqlite.rsafter theBackendimpl, asimpl EngineWindowState for SqliteBackend. The pin clauses and the sweep-lock body are absent by construction — nothing ofEngineFleetStateis implementable or referenced on this engine (ADR-012 §5's sqlite row: the single-flighter is the in-process sweep lease onGcHome, a sqlite fleet is a recorded non-option). - Timestamp encoding (recorded design point):
visible_aftertravels 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. Helperstime_to_nanos/nanos_to_timesit besidesize_u64insrc/sqlite.rs. - Staging discipline: one
prepare_cachedupsert 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 IGNOREalone 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);RETURNINGorder is unspecified, so the returned keys are sorted for determinism. - Virgin-store tolerance split per the sqlite engine's recorded
posture:
window_takeis a read — a no-tables-yet database maps to empty via the existingis_no_such_tabletolerance;window_stageis a write — a tableless database surfaces the engine error rather than silently creating schema (the constructor-vs-lazy design point: store construction always wiresensure_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_windowitself — the store construction call (store-sqlite-construction) wiresensure_gc_schema, which is idempotent and createsgc_windowonly. The clause-level tests use anew_window_backend()fixture that mirrors that wiring. - The boundary contract (
visible_after <= now, inclusive) is contract-tested, including the nanosecond slack row (visible atnow + 1nsstays).
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,
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.