Skip to content

refactor(gate): fold grants.ts's inline KeyedMutex into the shared one (#140) - #169

Open
TheBlackBit wants to merge 2 commits into
mainfrom
chore/140-dedup-keyed-mutex
Open

refactor(gate): fold grants.ts's inline KeyedMutex into the shared one (#140)#169
TheBlackBit wants to merge 2 commits into
mainfrom
chore/140-dedup-keyed-mutex

Conversation

@TheBlackBit

Copy link
Copy Markdown
Collaborator

In plain terms

The same small piece of code existed twice. This deletes one copy and points both users at the other.

What you're approving

No behaviour change and no public API change — the class is internal, not exported. One improvement comes along for free: the deleted copy never cleared its internal map, keeping one entry per grant for the life of the process; the surviving copy clears entries once nothing is waiting.

How to test

npm run test && npm run build

484/484 pass, build clean.


For reviewers — the detail

Two pull requests each needed a per-key async serializer and merged ~2h apart on 2026-07-28: #103 added the shared ceremony/keyed-mutex.ts, and #135 added an equivalent inline KeyedMutex in grants.ts. Both serialize a read-check-write on the same key so two concurrent callers can't both pass an "already done?" check and each act — double-settle for orders, double-spend for grants.

Three files:

  • ceremony/keyed-mutex.tskeyed-mutex.ts (git-tracked rename). ceremony/ is the home for authorization rails — passkey, dc-payment, credential-gate — and a generic serializer is not a rail, so it moves up a level now that grants.ts depends on it too. Header generalized to document both call sites and keep the in-process-only fencing.
  • grants.ts — inline class deleted, shared one imported.
  • ceremony/completion.ts — import path updated.

On the guard being load-bearing (CLAUDE.md: a test that still passes with the control removed is not a useful test). Verified rather than assumed — replacing KeyedMutex.run with return fn() fails 3 tests across both call sites:

Closes #140

🤖 Generated with Claude Code

Ever Morales and others added 2 commits August 5, 2026 15:59
#140)

PR #103 (delegated payments) added a shared `ceremony/keyed-mutex.ts` and PR
#135 (grants correctness) added a byte-for-byte equivalent inline `KeyedMutex`
inside `grants.ts` — merged ~2h apart on 2026-07-28, so `main` carried both.
Two copies of a concurrency control guarding money means a future hardening
lands in one and silently misses the other.

- Promote the file to `src/keyed-mutex.ts`. `ceremony/` is the home for
  authorization rails (passkey, dc-payment, credential-gate); a generic
  per-key serializer is not a rail, and `grants.ts` is not a ceremony.
- Delete the inline copy in `grants.ts`; import the shared one.
- Generalize the header to document BOTH call sites (order id for
  `completeOrder` #103, grant id for spends #104) and keep the in-process-only
  fencing.

Behaviour is identical, with one improvement: the shared implementation drops
a key's map entry once nothing is queued behind it, while the inline copy
retained one entry per grant id for the process lifetime.

Verified the guard is load-bearing rather than assumed: neutering
`KeyedMutex.run` to `return fn()` fails 3 tests across both call sites
(1 in completion.test.ts, 2 in grants.test.ts). Restored, full gate suite
484/484 green, `npm run build` clean.

Closes #140

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Ever Morales <ever.morales@koombea.com>
…140)

The shared `keyed-mutex.ts` header already documents both call sites and the
in-process-only fencing; restating it at the import site duplicates what the
dedup was meant to remove, and the surrounding imports carry no comments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Ever Morales <ever.morales@koombea.com>
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
credentagent-demo Ready Ready Preview Aug 5, 2026 10:02pm

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.

Dedup: fold grants.ts's inline KeyedMutex into the shared ceremony/keyed-mutex.ts once PR #103 lands

1 participant