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
Owner

claim_task was a blind UPDATE; two agents racing the same task both won (last-writer-wins). Now guarded on status = queued so claiming is atomic and exclusive — racing agents get a Conflict (ok:false over the socket) instead of stealing a claimed task. This is the contention the Tailscale bridge exposes for Phase 5.

Tests: test_claim_task_is_exclusive/test_claim_task_not_found (store), socket_rejects_double_claim_of_same_task (daemon, end-to-end). Plan Gap 4 moved to closed.

🤖 Generated with Claude Code

claim_task was a blind UPDATE; two agents racing the same task both won (last-writer-wins). Now guarded on `status = queued` so claiming is atomic and exclusive — racing agents get a Conflict (ok:false over the socket) instead of stealing a claimed task. This is the contention the Tailscale bridge exposes for Phase 5. Tests: `test_claim_task_is_exclusive`/`test_claim_task_not_found` (store), `socket_rejects_double_claim_of_same_task` (daemon, end-to-end). Plan Gap 4 moved to closed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
clawdie added 1 commit 2026-06-25 17:33:13 +02:00
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
6ed6b82949
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>
clawdie merged commit 95bf3f396d into main 2026-06-25 17:33:17 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: clawdie/colibri#190
No description provided.