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

Make Film Club room mutations atomic - #28

Merged
WalksWithASwagger merged 1 commit into
mainfrom
cursor/atomic-club-room-mutations-cb37
Sep 20, 2026
Merged

WalksWithASwagger merged 1 commit into
mainfrom
cursor/atomic-club-room-mutations-cb37

Conversation

@WalksWithASwagger

@WalksWithASwagger WalksWithASwagger commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

Closes #18.

Outcome

Film Club create/join/submit/delete no longer use unconstrained whole-room read/modify/write. Routes call a small atomic store API so concurrent successful writes are preserved, capacity and create-if-absent are enforced in the mutation, and a submit racing a delete cannot resurrect a room.

Stored history is unchanged: same room:{code} keys, same room JSON shape, no TTL, no key migration, no production rewrite.

Approach

  • Memory store: per-code lock plus cloned snapshots.
  • Redis: official Upstash SET NX for create-if-absent, and a bounded Lua compare-and-swap (createScript / EVALSHA). Lua does not re-encode rooms with cjson, so empty arrays and existing critiques are not rewritten by the script.
  • Authorization (member token / owner token) is rechecked inside the mutation.
  • Bounded retries only: 5 create-code attempts, 8 CAS attempts. Failures return 409/503 without logging private payloads.
  • Production unconfigured-store behavior is unchanged (isStoreConfigured()).

Route consumers enumerated

Route Old write API New API
GET /api/club/rooms/[code] get get (detached snapshot)
POST /api/club/rooms get + set createIfAbsent
POST .../join get + set joinMember
POST .../submit get + set (could fall back to a stale room after delete) appendSubmission
DELETE /api/club/rooms/[code] get + del deleteIfOwner

set/del are no longer on the write API.

Tests

Deterministic interleavings covered at store and actual route level: join/join, submit/submit, join/submit, submit/delete, create collision, duplicate member update, capacity race, snapshot isolation, legacy critique readability, and safe unavailable errors.

Focused command:

npx tsx --test tests/club-store.test.ts tests/club-rooms.test.ts tests/club-submit.test.ts

Verification

Check Result
npm run typecheck pass
npm run lint pass
npm test pass, 50 Node tests
Focused Club tests pass, 21 tests (20 memory/route + 1 Redis skip)
npm run build pass
npm run test:browser pass, 36 Chromium checks (desktop + mobile). First attempt failed because Playwright browsers were not installed in this environment; passed after npx playwright install chromium.
Redis integration (CLUB_TEST_REDIS_URL + CLUB_TEST_REDIS_TOKEN + CLUB_TEST_NAMESPACE) unverified — no dedicated test Redis in this environment. Memory-only passes are not Redis concurrency evidence. Command and skip are documented in docs/film-club.md.

Smoke/search checks were not run; #18 does not require them and they need a live server.

Hard gates

  • No data migration or history rewrite.
  • No secrets committed or logged.
  • Do not merge under this packet.

Rollback

A code revert restores the old racy writers against the same keys and shape. It does not rewrite stored rooms. Rooms mutated after deploy are still valid legacy JSON.

Open in Web Open in Cursor 

Replace whole-room route read/modify/write with create-if-absent, join, append, and owner-delete so concurrent writes cannot clobber each other or resurrect a deleted room. Keep existing Redis keys and room JSON; do not migrate history.

Co-authored-by: Kris Krüg <WalksWithASwagger@users.noreply.github.com>
@vercel

vercel Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
wedges Ready Ready Preview Sep 20, 2026 9:48pm UTC

Request Review

@WalksWithASwagger
WalksWithASwagger marked this pull request as ready for review September 20, 2026 22:55
@WalksWithASwagger
WalksWithASwagger merged commit 7a0229e into main Sep 20, 2026
3 checks passed
@WalksWithASwagger
WalksWithASwagger deleted the cursor/atomic-club-room-mutations-cb37 branch September 20, 2026 22:55
WalksWithASwagger added a commit that referenced this pull request Sep 21, 2026
Update D9–D12, prune merged vercel.json branch guards, and delete unused create-next-app SVGs. Leave C3 rate-limit type exports and open #22/#28 product work untouched.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kris Krüg <WalksWithASwagger@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — a19bc339 Deployed Sep 20, 2026 by vercel[bot]
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.

Make Film Club room mutations atomic without changing stored room history

2 participants