sqlite: run_schedules' failed-renewal arm classifies as Database, never LeadershipLost (review 004 item 9) — a lost lease (Ok(false)) keeps the respawn arm unchanged; a failed renewal (closed store / storage failure) propagates its opaque classification, so respawning misdirects at a dead store no more; dated (2026-10-11) ADR-017 §2 class-1 annotation of the loss-vs-failure arm set in ADR-009 §1, core-contract §Errors, queues.md, engine-sqlite.md, core+sqlite doc comments; two tests pin both arms; pg twin recorded for follow-up; task -> completed

This commit is contained in:
glm-5.3-flash committed 2026-10-11 11:07:44 +00:00
1 parent acdef94058
commit 9a9ccf26e0
8 files changed
+281 -21

No files matched your search

@@ -1,7 +1,7 @@
---
id: sqlite-fix-scheduler-error-classification
name: Classify run_schedules' renew-failure arms (review 004 item 9)
status: pending
status: completed
depends_on: []
scope: narrow
risk: low
@@ -35,17 +35,17 @@ the observable error surface, per AGENTS.md's ADR-wins discipline.
## Acceptance Criteria
- [ ] The arm set is decided and recorded in Notes (which error maps
- [x] The arm set is decided and recorded in Notes (which error maps
where, citing the contract text that pins `run_schedules`' error
surface); the closed-store arm no longer reports
`LeadershipLost`
- [ ] The window state was verified and recorded; a dated annotation
- [x] The window state was verified and recorded; a dated annotation
landed if class-1, or user sign-off if post-publish
- [ ] A test pins the closed-store arm (and the genuine
- [x] A test pins the closed-store arm (and the genuine
leadership-lost arm's unchanged disposition)
- [ ] The documented respawn recipe's text (wherever it lives) matches
- [x] The documented respawn recipe's text (wherever it lives) matches
the new classification
- [ ] `cargo test -p alkstore-sqlite`, clippy `-D warnings`, fmt
- [x] `cargo test -p alkstore-sqlite`, clippy `-D warnings`, fmt
clean; workspace gates green server-less
## References
@@ -58,8 +58,74 @@ the observable error surface, per AGENTS.md's ADR-wins discipline.
## Notes
> To be filled by implementation agent
- **Window state (verified 2026-10-11)**: `git tag -l` is empty — no
publish tag exists, the class-1 window is open. The classification
landed as a dated ADR-023 §2-style annotation (2026-10-11,
amend-in-place per ADR-017 §2 class 1); post-publish sign-off was
not needed.
- **The arm set (decisions of record)** — citing the contract text
that pins `run_schedules`' error surface (core-contract.md §Errors:
`LeadershipLost` is "`run_schedules` return on leadership loss";
`Database` is the opaque fallback with engine detail preserved via
the source chain; ADR-009 §1 pins the respawn recipe on the loss):
- `renew` → `Ok(false)` — the genuine loss arm (the lease expired
and was re-acquired elsewhere; exclusion lapses silently at TTL
expiry, ADR-008 §7) — returns `Err(LeadershipLost)`, unchanged,
return-before-tick. The respawn recipe matches on this arm only.
- `renew` → `Err(e)` — the machinery never reached the lock
semantics; not a loss, never `LeadershipLost`. The `Err`
propagates unchanged: the closed-store arm arrives pre-classified
(SqliteLockHandle::renew checks the closed sign first and fails
closed with the engine-wide `Database` posture, source "the
store is closed" — the same classification every other entry
point and the tick's writer-acquire arm already report), and any
other storage failure carries the driver's source chain.
- No new variant minted — ADR-008 §5's act-differently rule holds
(`Closed` stays the wake-receiver variant; closed store is
`Database` engine-wide).
- **Engine notes**: the closed-store entry checks (`run_schedules`
top, lock `renew`/`release`/`try_lock`, tick's `writer.acquire`
via `ok_or_else(closed_store_error)`) already reported `Database`,
so the pre-annotation defect was solely the mid-run
`unwrap_or(false)` flattening. Mem's renew is infallible
(`Ok(bool)`) — no failure arm to classify; the ADR-009 annotation
covers that shape explicitly.
- **Unresolved twin (for a pg follow-up task)**:
`alkstore-postgres/src/scheduler.rs:682` carries the identical
`.unwrap_or(false)` flattening — post-close renew there fails
closed with `Database` (pinned by pg lock_tests) but a mid-run
renewal failure still misreports `LeadershipLost`. Review item 9
recorded the sqlite finding only; the contract annotation now
applies to both engines, so pg is divergent until a twin task
discharges it. Not fixed here (task scope is narrow/sqlite; pg
tests need the harness server).
- **Docs aligned**: core-contract.md §Errors, ADR-009 §1 (the dated
annotation of record), queues.md's runner bullet,
engine-sqlite.md's scheduler/outbox map row, core
`Store::run_schedules` doc comment, and the sqlite scheduler's
module doc — all state the loss-vs-failure arm set; the respawn
recipe text elsewhere ("the caller's recipe is to respawn",
matching on `LeadershipLost`) stays accurate since the loss arm is
unchanged.
## Summary
> To be filled on completion
The sqlite leader loop's top-of-iteration renew no longer flattens a
failed renewal into `LeadershipLost`: `Ok(false)` keeps the
`Err(LeadershipLost)` respawn arm unchanged, and a failed renewal
propagates its opaque `Database` classification unchanged (closed
store carries the engine-wide "the store is closed" source) —
respawning a leader against a dead store is no longer the documented
outcome. Landed with the dated (2026-10-11) classification
annotation in ADR-009 §1, core-contract.md §Errors, queues.md,
engine-sqlite.md, and the core/sqlite doc comments. Two new
acceptance tests pin the arms: `closed_store_run_reports_the_closed_
classification_not_leadership_lost` (a mid-run close exits with the
closed `Database` classification, never `LeadershipLost`) and
`mid_run_lease_loss_still_returns_leadership_lost` (a deleted lease
mid-run still returns the loss, the respawn arm unchanged). Verified:
`cargo test -p alkstore-sqlite` (203+25 green, both new pins pass),
workspace `cargo test` green server-less, clippy `-D warnings` clean,
`cargo fmt --check` clean, doc gate (`RUSTDOCFLAGS="-D warnings"`
cargo doc) clean, fuzz corpus replay green. The pg twin
(`scheduler.rs:682`) is recorded in Notes as a follow-up.