---
name: msg-identity-w4-carrier-claim
description: MSG-IDENTITY W4 carrier-claim (REQ-CARRIER-CLAIM-EXCLUSIVE + REQ-RELAY-NO-BUSY-DELIVER) test patterns — deterministic one-winner unit + two-thread WAL race int in spt-store
metadata:
  type: project
---

W4 carrier-claim exclusive-take fix (crates/spt-store/src/spool.rs `claim_rows` BEGIN IMMEDIATE kernel; all take legs ride it; `release_at` clears taken_* in-txn). Tests written per doyle ruling (.claude/doyle-to-todlando.md §2).

**Key insight — where the teeth are:** the deterministic one-winner UNIT test (`concurrent_take_yields_exactly_one_winner`) is SEQUENTIAL (leg1 claims, then leg2 reads delivered=1) — it passes on OLD non-atomic code too, because a sequential second call always sees the committed UPDATE. It guards the exclusive *semantics* at the API level (doyle's chosen shape; busy_timeout makes true block-testing flaky). The real regression teeth against the field race live in the INT test.

**Int test** (`crates/spt-store/tests/carrier_claim_int.rs`, new tests/ dir — spt-store had none): two threads hammer the two take legs (hook-poll `drain_active_window_audited_at` window='default' + idle-edge `claim_idle_edge_audited_at` deferred=0, both include_deferred=false so they compete for the same default rows) against ONE real spool.db under WAL while a producer spools N=100 fresh unique-body rows. Assert union of both legs' takes == produced set, no body taken by both. On pre-fix autocommit SELECT-then-UPDATE both threads read delivered=0 in their WAL snapshots and both take the row → dup → fails. Termination: consumers break only on empty-batch AND producer_done AtomicBool (once done, all N committed, so an empty read = all delivered — no lost rows); 30s deadline guard. Track by unique body string (drain_active_window returns body only, no id).

**release rider unit** (`release_clears_taker_audit_then_retake_restamps`): claim+stamp, release_at, assert audit_rows_at shows taken_leg/sid/at_ms NULL AND delivered=0, then re-take by a DIFFERENT leg re-stamps. Guards the field misattribution (row read delivered=1 taken_leg='idle-inject' after busy-agent claim/release).

**RELAY-NO-BUSY unit** (`poll_taken_row_never_idle_injected_but_untaken_row_still_claimable`): reduced ordering assertion — after drain_active_window takes a row, claim_idle_edge returns empty; plus F-023/IDLE-PARKED stays green (untaken default row IS idle-edge-claimable).

Verify cmds (all exit 0, ≤4s each): `cargo test -p spt-store --lib spool` (20 pass), `cargo test -p spt-store --test carrier_claim_int`, `cargo clippy -p spt-store --all-targets -- -D warnings`, `traceable-reqs check`. spt-store is a LIB crate (unlike bin-only spt) so tests/ integration files use `spt_store::spool::` public API directly — no daemon, no CARGO_BIN_EXE. Did NOT run the spt daemon e2e suite (idle_edge_drain_e2e etc.) — deadlock risk per [[daemon-lib-tests-deadlock-on-live-host]], and those are unrelated to claim/release.
