Skip to content

fix(sdk): make pending-approval consumption atomic - #1890

Open
ra-co88 wants to merge 1 commit into
UsefulSoftwareCo:mainfrom
ra-co88:fix/approval-consume-atomic
Open

fix(sdk): make pending-approval consumption atomic#1890
ra-co88 wants to merge 1 commit into
UsefulSoftwareCo:mainfrom
ra-co88:fix/approval-consume-atomic

Conversation

@ra-co88

@ra-co88 ra-co88 commented Aug 30, 2026

Copy link
Copy Markdown

What

Pending-approval consumption is atomic: the blob that marks a pending approval is removed with a compare-and-delete whose single winner is the consumer. BlobStore gains compareAndDelete(namespace, key) — true iff this caller's delete removed an existing record.

Why

Approvals are single-use decisions. A read-then-delete pair has a window where two concurrent requests both read the pending approval and both proceed — double execution on one human decision. The compare-and-delete contract guarantees exactly one concurrent caller observes true; the loser sees absent-after-commit.

What changed

  • BlobStore.compareAndDelete contract (fail-closed semantics documented on the interface).
  • FumaDB implementation: get+delete inside fuma.transaction (real BEGIN/COMMIT on libSQL/Postgres — the serialization is the guarantee).
  • In-memory implementation: single synchronous Map op.
  • R2 implementation (Cloudflare host): R2 offers no conditional delete, so this is isolate-scoped single-winner (a claim-set gate closing the intra-isolate await window, plus head-then-delete). Residual: cross-isolate races are last-writer-wins; tolerated because the caller pattern is single-consume-per-approval with idempotent re-consume returning null.
  • The approval consume path gates on compareAndDelete.

Test plan

Atomicity suite: concurrent consumers — exactly one wins; loser observes absent; no double-execution path. 4 tests green against current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants