Skip to content
This repository was archived by the owner on Aug 10, 2026. It is now read-only.

fix(agent): re-enable the CAS single-claim guard (channelQueueStoreFor dropped ifUpdatedAt) - #128

Merged
unforced merged 1 commit into
mainfrom
ag-agent-cas-fix
Jun 22, 2026
Merged

fix(agent): re-enable the CAS single-claim guard (channelQueueStoreFor dropped ifUpdatedAt)#128
unforced merged 1 commit into
mainfrom
ag-agent-cas-fix

Conversation

@unforced

Copy link
Copy Markdown
Contributor

The bug (found by the deep audit — production correctness)

The single-claim guard (agent#101 / PR #116) — which stops two connected sessions from both claiming the same inbound message — was silently disabled in production.

channelQueueStoreFor (daemon.ts) wired the store's setInboundStatus as a 3-param arrow that dropped the 4th ifUpdatedAt arg:

setInboundStatus: (id, status, claimedAt) => vt.setInboundStatus(id, status, claimedAt),

VaultTransport.setInboundStatus does a compare-and-set (if_updated_at) only when ifUpdatedAt is supplied, otherwise force:true (last-write-wins). With the arg dropped, every claim took the force path → CAS off → the double-claim race re-opened for channel-backend agents.

Why nothing caught it: the type checker can't (a narrower arrow is assignable to the wider interface slot), and the unit tests inject a fake ChannelQueueStore that honors all four args — only the live daemon adapter was lossy.

Fix

Forward all four args (one line). Plus a new regression test that exercises the real adapter against a VaultTransport (records the PATCH body):

  • with ifUpdatedAtif_updated_at CAS body (not force)
  • without it → force:true (the release/handled/sweep path — unchanged)

This is the test class the audit flagged as missing: assert the production adapter, not just the fake store.

Gate

tsc --noEmit clean; bun test ./src 1022 pass / 0 fail.

…he CAS single-claim

The production adapter wiring the pull-queue to a VaultTransport
(channelQueueStoreFor, daemon.ts) declared `setInboundStatus` as a 3-param arrow
`(id, status, claimedAt) => vt.setInboundStatus(id, status, claimedAt)` — silently
DROPPING the 4th `ifUpdatedAt` arg. VaultTransport.setInboundStatus does a CAS
(`if_updated_at`) only when that arg is present, else falls back to `force:true`
(last-write-wins). So in production every claim was force:true → the compare-and-set
single-claim guard (agent#101, the whole point of PR #116) was SILENTLY DISABLED, and
the double-claim race (two connected sessions grabbing the same inbound) was re-opened
for channel-backend agents.

The bug was invisible to the type checker (a narrower arrow is assignable to the wider
interface slot) and to the tests (they inject a FAKE ChannelQueueStore that honors all
four args — only the live daemon adapter was lossy).

Fix: forward all four args. New test exercises the REAL adapter against a VaultTransport
(records the PATCH body): with ifUpdatedAt → `if_updated_at` CAS (not force); without it
→ `force:true` (the release/handled/sweep path, unchanged).

Found by the agent-module deep audit. Gate: typecheck clean; `bun test ./src` 1022 pass / 0 fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@unforced
unforced merged commit 01af2d0 into main Jun 22, 2026
@unforced
unforced deleted the ag-agent-cas-fix branch June 22, 2026 14:07
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant