83 lines
3.6 KiB
Markdown
83 lines
3.6 KiB
Markdown
---
|
||
id: suite-tx-commit-atomicity-rows
|
||
name: Contract-suite rows — outbox/keyed-publish tx commit-atomicity + with_tx panic probe
|
||
status: pending
|
||
depends_on: []
|
||
scope: moderate
|
||
risk: low
|
||
impact: phase
|
||
level: implementation
|
||
tags: [wave-5, contract-suite, tx-seam]
|
||
---
|
||
|
||
## Description
|
||
|
||
Add the tx-seam commit-atomicity rows to
|
||
`alkstore-contract-suite/src/properties.rs` and wire them into both
|
||
engines' suite targets, discharging three backlog rows
|
||
(core-contract.md §Verification backlog): "`outbox_enqueue_tx`
|
||
commit-atomicity on both engines" (ADR-014), "`publish_with_key_tx`
|
||
commit-atomicity on both engines" (ADR-015 §2), and the N-5
|
||
`with_tx` panic-disposition probe (the waves-1–2 general review's
|
||
ordered wave-5 add — the panic path "can only be fully pinned once a
|
||
real engine's handle exists").
|
||
|
||
Rows to add:
|
||
|
||
- **`outbox_enqueue_tx_commit_atomicity`** — rollback drops the
|
||
backing-queue job row together with the business write (no ghost
|
||
job; `run_once` afterwards claims nothing); commit makes the job
|
||
claimable by `run_once` exactly when the business write commits
|
||
(drive a real delivery through the `Delivery` closure); the stamped
|
||
opts are the outbox's derived 60/5/5 set, `get_job`-visible and
|
||
identical on both engines (ADR-014 §1, ADR-010 §3a). The
|
||
reserved/empty outbox-name validation legs already pin in the
|
||
exemplar row — do not duplicate them.
|
||
- **`publish_with_key_tx_commit_atomicity`** — rollback drops the
|
||
keyed event row with the business write (no ghost event); commit
|
||
makes it visible to `read_since` (and a subscriber attach); the key
|
||
round-trips on the committed event. The empty-`Some`-key
|
||
`InvalidName` leg already pins in the exemplar — do not duplicate.
|
||
- **`with_tx_panicking_closure_rolls_back`** — a closure that panics
|
||
mid-flight ⇒ rollback with no residue (the uniform no-ghosts list:
|
||
job/event/notify/offset — ADR-021 §4's drop = rollback through the
|
||
panic path), and the store remains usable afterward (the SQLite
|
||
writer slot replenished — the wave-3 stranding fix's property, now
|
||
pinned at contract level). Mechanics hint: the panic crosses an
|
||
await inside `with_tx`'s own future, so drive it via
|
||
`tokio::spawn` + `JoinError::is_panic()` (a `catch_unwind` around an
|
||
async closure does not see the panic point); assert the panic
|
||
surfaced *and* the post-panic state. This is N-5's probe against
|
||
real engines for the first time — the SQLite handle-on-lease Drop
|
||
impl and the pg pooled-object discard arm must both survive it.
|
||
|
||
## Acceptance Criteria
|
||
|
||
- [ ] Three rows exist, version-stamped (ADR-014 §1, ADR-015 §2,
|
||
ADR-021 §4, ADR-007 as applicable)
|
||
- [ ] Rows wired into both engines' `contract_suite.rs` targets
|
||
- [ ] SQLite column green server-less; pg column green against the
|
||
harness server
|
||
- [ ] The panic probe passes on both engines (no writer-slot stranding,
|
||
no pooled-object leak) — if an engine fails here, that is a real
|
||
defect: stop, record, fix engine-side before completing the task
|
||
- [ ] `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 (outbox tx
|
||
commit-atomicity; keyed-publish tx commit-atomicity)
|
||
- docs/architecture/decisions/014-outbox-tx-enqueue.md §1
|
||
- docs/architecture/decisions/015-streams-depth.md §2
|
||
- docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md §4
|
||
- docs/reviews/001-waves-1-2-general-review.md (N-5)
|
||
- tasks/sqlite-engine-seam-tx.md (the Drop impl N-5's probe exercises)
|
||
|
||
## Notes
|
||
|
||
> To be filled by implementation agent
|
||
|
||
## Summary
|
||
|
||
> To be filled on completion |