200 lines
10 KiB
Markdown
200 lines
10 KiB
Markdown
---
|
||
id: sqlite-engine-integration
|
||
name: SQLite engine — integration (lint removal, full-surface wiring, suite adoption)
|
||
status: completed
|
||
depends_on: [sqlite-engine-notify-listen, sqlite-engine-streams, sqlite-engine-queues, sqlite-engine-locks, sqlite-engine-scheduler-outbox]
|
||
scope: moderate
|
||
risk: medium
|
||
impact: phase
|
||
level: implementation
|
||
tags: [wave-3, sqlite-engine, integration]
|
||
---
|
||
|
||
## Description
|
||
|
||
Close the wave's integration gaps once every mechanism is wired:
|
||
|
||
- **Remove the two lint suppressions** in
|
||
`alkstore-sqlite/src/substrate/mod.rs` (`#![allow(dead_code)]`,
|
||
`#![allow(unused_imports)]`) — the waves-1–2 review's explicit
|
||
wave-3 obligation. With the engine layer wired, every substrate
|
||
surface should be reachable; genuinely dead ported code must be
|
||
**cut, not suppressed** (and the cut registered in PROVENANCE.md if
|
||
it diverges from the lineage's kept set — ADR-018's delta
|
||
discipline). Fix whatever the lints surface; do not re-add allows.
|
||
- **Full-surface sweep**: every `Store`/`TxHandle`/mechanism trait
|
||
method implemented (no `todo!`/`unimplemented!` anywhere); the
|
||
engine crate's lib re-exports its public surface (`open`,
|
||
`SqliteOpts`, the concrete store type) per the module-per-file
|
||
convention.
|
||
- **Contract-suite adoption** (the plan's "waves 3 and 4 adopt the
|
||
harness"): implement `StoreFactory` for the SQLite engine (fresh
|
||
temp-file store per `open`, idempotent teardown) and wire the
|
||
engine's backlog column — the rows this engine owns now, per
|
||
ADR-023's verification-backlog additions and the engine-scoped
|
||
backlog rows:
|
||
- Extent-clamp semantics (`claim_batch(n <= 0)`, stream reads
|
||
`limit <= 0`) — stamped `ADR-023 §2`
|
||
- Duration-refusal (`try_lock`/`renew` with `ttl <= 0`) — stamped
|
||
`ADR-023 §2`
|
||
- `encode_payload` typed-failure round-trip (enqueue/publish store
|
||
+ decode the exact serialization) — stamped `ADR-023 §1`
|
||
- Plain-path open (`?name=value` suffix = literal filename) —
|
||
stamped `ADR-023 §3`
|
||
- Poll-cadence default + knob (config-surface accounting, not
|
||
wall-clock) — stamped `ADR-023 §4`
|
||
- The engine-scoped rows core-contract.md assigns this engine:
|
||
`PayloadTooLarge` never produced (ADR-016 §5), drop = rollback
|
||
no-ghosts (ADR-021 §4), in-tx read-your-own-writes (ADR-021 §1),
|
||
enqueue-opts resolution (ADR-020 §1–§3), receiver close arms
|
||
(ADR-021 §5) — each stamped per the suite's convention.
|
||
Rows run against the SQLite factory now; wave 5 runs the same rows
|
||
against pg (the factory-parameterized point).
|
||
- **Crate docs**: the engine crate's lib-level doc comments state the
|
||
single-host posture and the writer-parking honesty note (ADR-016,
|
||
ADR-007's negative consequence) — the identity statements this
|
||
crate owns.
|
||
- **Gates**: full workspace build/test/clippy/fmt; coverage spot-check
|
||
on the engine crate (no large uncovered regions outside error arms).
|
||
|
||
## Acceptance Criteria
|
||
|
||
- [x] Both `#![allow]` lints removed from `substrate/mod.rs`; any
|
||
code the removal surfaces is cut (and registered) or wired —
|
||
clippy `-D warnings` green without them
|
||
- [x] No `todo!`/`unimplemented!` in the engine crate; full trait
|
||
surface implemented
|
||
- [x] `StoreFactory` implemented for SQLite; the backlog-column rows
|
||
listed above exist, version-stamped, and run green against the
|
||
SQLite factory
|
||
- [x] Engine crate lib docs carry the single-host + writer-parking
|
||
posture statements
|
||
- [x] Workspace gates green: `cargo build`, `cargo test`, clippy
|
||
`-D warnings`, fmt clean
|
||
|
||
## References
|
||
|
||
- docs/reviews/001-waves-1-2-general-review.md (§2 smells, §7)
|
||
- docs/architecture/decisions/023-fourth-review-round.md (Verification backlog additions)
|
||
- docs/architecture/core-contract.md (§Verification backlog)
|
||
- docs/architecture/decisions/022-contract-suite-layout.md
|
||
- docs/architecture/decisions/016-deployment-honesty.md
|
||
- alkstore-contract-suite/src/factory.rs
|
||
|
||
## Notes
|
||
|
||
> Decisions of record the description didn't pin:
|
||
|
||
- **Lint removal cut six substrate items, registered D-32..D-36** —
|
||
lifting the two `#![allow]`s surfaced six genuinely dead surfaces,
|
||
all cut rather than wired, each an ADR-018 register entry with its
|
||
reason: `arg_opt_i64` (upstream consumed it at the optional-arg SQL
|
||
entry points whose queue functions D-04 dropped — the re-derivation
|
||
resolves opts engine-side), `ops::now_unix` (the fold D-17 gave
|
||
each module region its own clock read; `resolution.rs` owns the
|
||
engine layer's single clock), `queue_next_claim_at` (upstream's
|
||
external-poll-driver function; the v1 scheduler surface has no
|
||
next-wake query — the engine's leader loop derives the boundary
|
||
from `scheduler_tick` + `scheduler_soonest`), `Writer::try_acquire`
|
||
(a try-shaped begin doesn't exist on the contract — `begin_tx`
|
||
*parks* on the lease by design, ADR-007; a try-acquire would
|
||
contradict the posture), and `UpdateWatcher::spawn` /
|
||
`SharedUpdateWatcher::new` (the config-less convenience twins —
|
||
this engine's single open posture always constructs
|
||
`WatcherConfig` from `SqliteOpts`, ADR-023 §4; a second
|
||
config-less path would recreate the mixed-posture shape D-29
|
||
resolved). None changed kept-fidelity posture — all six are
|
||
`drop`-category entries against the *kept* set, with the affected
|
||
substrate tests re-expressing their properties through the
|
||
reachable surface (no assertion strength lost: the probe tests
|
||
test the same coercion/lease behavior through the surviving forms).
|
||
- **Two substrate items kept under `#[cfg(test)]`** rather than cut:
|
||
`SharedUpdateWatcher::subscriber_count` and the
|
||
`DEFAULT_WATCHER_POLL_INTERVAL` re-export — engine-side tests
|
||
reach them (the leak/no-leak pins, the 1 ms default pin); they are
|
||
test-observation surface, honestly gated `#[cfg(test)]`, not
|
||
suppressed. `open_store` was likewise promoted `pub(crate)` (the
|
||
store tests construct the concrete handle; `open` stays the
|
||
consumer surface).
|
||
- **The exemplar row had a real-engine sequencing defect — fixed
|
||
suite-side** (a suite-text change, ADR-017 §2 class 4): the
|
||
name-validation row held its `tx` handle alive across the whole
|
||
battery including the final `with_tx` leg. The mock harness never
|
||
saw this; a real engine's `begin_tx` parks a concurrent begin on
|
||
the writer slot (ADR-007's honest model), so the row deadlocked a
|
||
real factory. The tx battery is now scoped so the handle drops
|
||
before the `with_tx` leg. The row's *assertions* are unchanged —
|
||
only the sequencing fix — but the incident is the wave-5 lesson
|
||
the factory exists to surface: rows are mock-blind until an
|
||
executes them against a real single-writer engine.
|
||
- **Row set** (nine total — the exemplar + eight new, all in
|
||
`alkstore-contract-suite/src/properties.rs`, one owner,
|
||
version-stamped per the convention, each a public `pub async
|
||
fn(&dyn StoreFactory)`): the ADR-023-stamped rows (extent-clamp
|
||
including the boundary-totality legs, duration-refusal,
|
||
`encode_payload` round-trip), and the engine-scoped rows the task
|
||
names (PayloadTooLarge-never-produced — the SQLite arm, the pg
|
||
rejection arm rides wave 4's adoption of the same row text; the
|
||
drop=rollback no-ghosts; in-tx read-your-own-writes;
|
||
enqueue-opts resolution — ADR-020 §1–§3; receiver close/save arms
|
||
— ADR-021 §5). **Plain-path open (§3) and poll cadence (§4) pin
|
||
engine-side, not as suite rows**: both are constructor-level
|
||
SQLite-native facts not expressible over `StoreFactory::open()` —
|
||
`uri_shaped_open_path_is_a_literal_filename` and
|
||
`poll_interval_flows_to_the_watcher_config` (stamped,
|
||
`open_tests.rs`) are this engine's rows for them; wave 4's pg
|
||
column simply doesn't carry them (they're SQLite-scoped backlog
|
||
rows per core-contract.md).
|
||
- **The factory** (`alkstore-sqlite/tests/contract_suite.rs`): a fresh
|
||
never-before-used temp file per `open` under a per-instance
|
||
directory; teardown = directory delete, idempotent
|
||
(already-deleted ⇒ `Ok`). Its isolation/idempotence contract has
|
||
its own pin in the test target (`opens_are_isolated_and_teardown_is_idempotent`);
|
||
receiver-close rows drive the terminal-close arm by dropping the
|
||
store handle (the dispose carrier every engine has), not teardown —
|
||
deleting files under a live store is not a close mechanism.
|
||
- **Coverage spot-check** (cargo-llvm-cov, engine crate): 93.59%
|
||
lines / ~89% regions, every file ≥85% lines; the misses are error
|
||
arms and Windows-only `file_id` variants
|
||
(`watcher.rs`'s HighRes/LowRes halves) — no large uncovered regions
|
||
outside error arms, the gate the task pinned.
|
||
|
||
## Summary
|
||
|
||
> Landed: the two `#![allow]` lints removed from
|
||
> `substrate/mod.rs` (its module docs re-stated to the wave-3 wired
|
||
> posture); the removal surfaced six dead surfaces — cut, each
|
||
> registered D-32..D-36 in `PROVENANCE.md` (queue-side: `arg_opt_i64`,
|
||
> `now_unix`, `queue_next_claim_at`; writer/watcher-side:
|
||
> `Writer::try_acquire`, `UpdateWatcher::spawn`,
|
||
> `SharedUpdateWatcher::new`), their probe tests re-expressed through
|
||
> the reachable surface; two test-observation items honestly
|
||
> `#[cfg(test)]`-gated (`subscriber_count`, the
|
||
> `DEFAULT_WATCHER_POLL_INTERVAL` re-export); no allows re-added —
|
||
> clippy `-D warnings` green without them.
|
||
>
|
||
> Contract-suite adoption: eight new rows in
|
||
> `alkstore-contract-suite/src/properties.rs` (extent-clamp +
|
||
> boundary-totality, duration-refusal, payload round-trip,
|
||
> `PayloadTooLarge`-never-produced SQLite arm, drop=rollback
|
||
> no-ghosts, in-tx read-your-own-writes, enqueue-opts resolution,
|
||
> receiver close/save arms) — all version-stamped, all re-exported
|
||
> from the suite lib. `store::SqliteFactory` implemented in the
|
||
> engine's new integration test target
|
||
> (`alkstore-sqlite/tests/contract_suite.rs`), running all nine rows
|
||
> (the exemplar + the eight) against the SQLite factory — 10 tests,
|
||
> green; the factory's isolation/idempotence contract pinned
|
||
> alongside. Found and fixed suite-side: the exemplar row's
|
||
> hold-the-tx-across-`with_tx` sequencing deadlocked any real
|
||
> single-writer factory (the mock never saw it).
|
||
>
|
||
> Engine crate lib docs: the posture statements surfaced under a
|
||
> `# Posture` heading — single-host (ADR-016) and writer-parking
|
||
> (ADR-007's negative consequence) spelled as the crate's identity
|
||
> statements.
|
||
>
|
||
> Verified: workspace `cargo build`/`cargo test` green (25 + 186 +
|
||
> 10 + 3 + harness), clippy `--workspace --all-targets -D warnings`
|
||
> clean, `cargo fmt --check` clean; engine-crate coverage 93.59%
|
||
> lines (cargo-llvm-cov), misses confined to error arms and
|
||
> Windows-only watcher variants. |