decompose wave 5 — contract suite: audit-first split of the verification backlog (engines' columns already discharge most rows; map in review-wave-5's appendix), seven mechanism-grouped suite-row tasks (queue depth, scheduler, tx commit-atomicity, streams, locks, wakes, opts/backoff equivalence), two engine-side hardening tasks (sqlite commit-error arm, pg F-1 defense-in-depth), and the review-wave-5 gate that flips the engine specs to stable

This commit is contained in:
glm-5.3-flash committed 2026-10-10 05:37:53 +00:00
1 parent 9a00fb8a7e
commit 250511d480
11 files changed
+911 -2

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
---
id: suite-lock-rows
name: Contract-suite rows — lock TTL/expiry re-acquisition + concurrent try_lock loser
status: pending
depends_on: []
scope: narrow
risk: medium
impact: phase
level: implementation
tags: [wave-5, contract-suite, locks]
---
## Description
Add the named-locks contract rows to
`alkstore-contract-suite/src/properties.rs` and wire them into both
engines' suite targets, discharging two backlog rows
(core-contract.md §Verification backlog): "Named-lock TTL/expiry
re-acquisition on SQLite" (pinned on pg by the POC's lock probe; on
SQLite it rests on the forked substrate's lock machinery — the suite
pins both engines to identical behavior) and "Concurrent `try_lock`
loser/error behavior on SQLite" (the substrate's busy-path under lock
contention is the thing to pin — the pg side returns cleanly).
Rows to add:
- **`lock_ttl_expiry_and_reacquisition`** — the ADR-008 §7 guarantee
row: mutual exclusion bounded by TTL + renewal. Pin: a held lock
excludes a second acquirer (`None`); after TTL expiry exclusion
lapses *silently* (no revocation event, no error — a second owner
acquires); the original holder's post-expiry `renew` is refused
(`false` — the deadline-lapse refusal, ADR-010 §2's uniform
predicate shape on the lock handle); `release` on the second owner
frees the name for a third acquirer. Short TTL (1 s) + tolerance
sleeps — sequential single-store, fits the determinism posture.
- **`concurrent_try_lock_loser_is_a_value`** — contention posture:
with a lock held, contender `try_lock` calls return the clean
no-work value (`None`) on **both** engines — never a `Database`
error, never a busy-throw surfacing (the SQLite substrate's
busy-path is the risk site; the pg side is the reference behavior).
Drive several contenders sequentially against one held lock, and a
release-then-contend cycle proving the loser path leaves no state
that blocks a later acquire.
Risk note: what the SQLite busy-path *actually* returns under
contention is the open question this row exists to answer — if it
surfaces `Database` where pg returns `None`, that is a real
conformance finding: stop, record it in Notes, and raise it (an
engine fix or an ADR-level asymmetry call) rather than pinning the
divergence silently.
## Acceptance Criteria
- [ ] Two rows exist, version-stamped (ADR-008 §7, ADR-019 §1,
ADR-023 §2 as applicable)
- [ ] Rows wired into both engines' `contract_suite.rs` targets
- [ ] SQLite column green server-less; pg column green against the
harness server
- [ ] Any engine divergence found is recorded in Notes with its
disposition (fix or documented asymmetry) — not pinned silently
- [ ] `cargo test -p alkstore-sqlite -p alkstore-postgres` green
(pg rows skip cleanly server-less); clippy `-D warnings`; fmt clean
## References
- docs/architecture/core-contract.md §Verification backlog (lock
TTL/expiry re-acquisition; concurrent try_lock loser)
- docs/architecture/decisions/008-contract-v1-pinning.md §7
- docs/architecture/decisions/019-mechanism-handle-surfaces.md §1
- docs/architecture/engine-sqlite.md (the substrate's lock machinery)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion