7.3 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | |||
|---|---|---|---|---|---|---|---|---|---|---|---|
| sqlite-commit-error-arm | SQLite engine — commit-error-arm coverage (wave-3 review's deferred test) | completed | narrow | medium | isolated | implementation |
|
Description
Land the wave-3 review gate's deferred coverage item
(tasks/review-wave-3.md Notes: "Coverage of the commit-error arm —
no test induces a failing COMMIT ... natural home is wave 5's suite
hardening"): a test that drives a failing COMMIT through the SQLite
engine's commit path and pins the fix the review verified by
code-read — the writer slot is replenished via the reopen closure on
the failed COMMIT (no stranding), the error surfaces as the opaque
Database, and the store remains fully usable afterward (subsequent
begin_tx/auto-commit ops work).
The injection mechanism is this task's to find — candidates: a
PRAGMA max_page_count squeeze forcing SQLITE_FULL on a
space-consuming commit, or a cfg(test) fault seam in the seam layer
if the PRAGMA route cannot hit the COMMIT arm deterministically. The
wave-4 fix batch's cfg(test) config-seam precedent
(pg-fix-forwarder-reconnect) is the house pattern if a seam is
needed. Prefer the least-invasive mechanism that deterministically
reaches the arm; document the choice.
If the same session has cheap room for it, the waves-1–2 review's optional add — the watcher reconnect-success path test (upstream's W-1 test drives only the failure path; "a reconnect success test would require a file appearing mid-run") — rides here only if the engine kept the current watcher shape and the test is genuinely cheap; otherwise leave it recorded as not-taken in Notes (it was a suggestion, not an order).
Acceptance Criteria
- A test induces a failing
COMMITon the SQLite engine and pins: error surfaces (Database), writer slot replenished (a subsequentbegin_txsucceeds), no partial-commit residue - The injection mechanism documented in Notes (PRAGMA vs seam, and why)
- The watcher reconnect-success test either landed or explicitly recorded as not-taken with the reason
cargo test -p alkstore-sqlitegreen server-less; clippy-D warnings; fmt clean
References
- tasks/review-wave-3.md (Notes: the deferred commit-error-arm coverage)
- tasks/sqlite-engine-seam-tx.md (the
commitreplenish fix the test pins) - tasks/pg-fix-forwarder-reconnect.md (the
cfg(test)seam precedent) - docs/reviews/001-waves-1-2-general-review.md §2 (the watcher reconnect-success suggestion)
Notes
Decisions of record the implementation made that the description didn't pin:
- Injection mechanism: the
cfg(test)commit-fault seam, not the PRAGMA route — decided by live probe. Both PRAGMA candidates were tested against real SQLite before choosing: in both WAL and DELETE journal modes,PRAGMA max_page_countsqueezed to the current page count fails the first growth statement (SQLITE_FULL/DiskFullat page-allocation time), leaving "no transaction is active" for the subsequentCOMMIT— the commit arm is unreachable through PRAGMA-space. (Also probed:max_page_countis per-connection, so arming on the writer conn pre-begin_txwould have ridden into the tx connection — the route failed on placement of the error, not on delivery.) The seam substitutes aSQLITE_FULL-shapedrusqlite::Errorfor one commit and feeds it into the production commit error arm — the test pins the real drop +reopenreplenish code, not a replica. - Scoping design (the seam's cross-test-safety shape): the fault
flag is a per-
SqliteStoreArc<AtomicBool>(born disarmed, armed via the#[cfg(test)]arm_commit_fault, disarmed on first consumption — exactly one commit faults and every later commit is real, which the test also pins). Parallel test stores can never interfere. Plumbing follows thepg-fix-forwarder-reconnectprecedent exactly:#[cfg(test)]field onSqliteStoreand onSqliteTxHandle,#[cfg(test)]param onSqliteTxHandle::begin, cfg'd statement branches instore.rs::begin_txandsrc/tx.rs::commit— production builds compile the plain path. - Replay-proofed live: with the commit error arm's
writer_reopenreplenish temporarily removed, the new test fails (the nextbegin_txparks past its 5 s timeout — the stranding the review identified by code-read); reverted, it passes. - The watcher reconnect-success add rides here — taken. The
vanished-file route the waves-1–2 review sketched could not reach
the success body (on file reappearance the identity check reads a
fresh
(dev, ino)and the watcher dies through the dead-man's switch before the reconnect would matter). Instead the test drivesrun_poll_loopdirectly through theopen_conn_fnseam the loop already takes — the same instrument as the W-1 failure test — with the db file present throughout (identity stable): initial open and first two reconnects injected as failures, third reconnect succeeds, and a commit from a writer connection then wakeson_change(proving the success arm re-baselinesdata_versionand restores delivery). Watcher shape untouched. cargo build;cargo test -p alkstore-sqlitegreen server-less (191 lib + 25 suite, both new tests included); workspacecargo test399 passed / 0 failed (core 25 + harness 3; postgres 121 + 25 suite + 9 schema; sqlite 191 + 25 suite);cargo clippy --all-targets -- -D warnings;cargo fmt --check— all green.
Summary
What landed, verified how:
alkstore-sqlite/src/seam.rs: the#[cfg(test)]commit_faultmodule — per-storeFlag(Arc<AtomicBool>),disarmed/arm/take(disarm-on-consume), and theSQLITE_FULL-shaped fabricatedrusqlite::Error— with the mechanism-choice rationale (the PRAGMA probes) in its doc comment.alkstore-sqlite/src/tx.rs:#[cfg(test)]fault field onSqliteTxHandle+beginparam;commit's blocking body gains a cfg'd branch that feeds the fault into the existing production match — the error arm (drop +reopenreplenish,sqlite_errormapping) runs unmodified.alkstore-sqlite/src/store.rs:#[cfg(test)]commit_faultfield onSqliteStore, thearm_commit_faultsurface, and the cfg-branchedbegin_txcall.alkstore-sqlite/src/store/tx_tests.rs:failed_commit_replenishes_the_writer_slot— failedCOMMITerrs opaqueDatabasewith the SQLITE_FULL source chain; the nextbegin_txproceeds (slot replenished, no stranding); no partial-commit residue; the post-failure commit is real and clean (fault disarmed); auto-commitnotifyworks afterward.alkstore-sqlite/src/substrate/watcher.rs:reconnect_success_resumes_wake_delivery— the waves-1–2 review's optional reconnect-success add, driven through the loop'sopen_conn_fnseam (injected failed opens, then a successful reconnect; wake delivery resumes and is pinned). Recorded as taken per the task's optional clause.- Gates:
cargo build,cargo test(server-less: core 25 + core suite 25 + sqlite 191 + postgres 121 + 9 schema — 399 passed / 0 failed, postgres harness skipped server-less),cargo clippy --all-targets -- -D warnings,cargo fmt --check— all green.