fix(store): atomic+exclusive claim_task — close Gap 4 concurrency guard #190

Merged
clawdie merged 1 commit from fix/claim-task-concurrency-guard into main 2026-06-25 17:33:17 +02:00

1 commit

Author SHA1 Message Date
6ed6b82949 fix(store): make claim_task atomic+exclusive (Gap 4 concurrency guard)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / port (pull_request) Has been cancelled
CI / agent-jail-pkgs (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
claim_task was a blind UPDATE (`WHERE id = ?`), so two agents racing to
claim the same task both 'succeeded' — last writer wins. This is the exact
contention the Tailscale bridge exposes once remote agents poll the board.

Guard the UPDATE on `status = 'queued'` so the claim is atomic: only the
first claimant matches a still-queued row; the rest match zero rows and get
a new StoreError::Conflict (surfaced as ok:false over the socket). A zero-row
result is disambiguated into NotFound vs Conflict.

Tests:
- test_claim_task_is_exclusive / test_claim_task_not_found (store)
- socket_rejects_double_claim_of_same_task (daemon, end-to-end over socket)

Plan: Gap 4 moved to closed. Store 11 green, board 4 green, clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 17:32:56 +02:00