Closer/app
null 23dd6a75e8 fix(games): atomic session start to prevent duplicate sessions on concurrent start (F-RACE-001)
Simultaneous game start by both partners created two divergent active sessions (TOCTOU: a
non-transactional check-then-create in GameSessionManager.startGameWithCouple). Each partner
ended up in a separate session with different questions → no shared reveal.

Fix: QuestionSessionRepository.startSessionAtomically runs a Firestore transaction on a
per-couple pointer doc (couples/{cid}/sessions/_active). It reads the pointer (+ the pointed
session) and either returns AlreadyActive (caller joins the existing session) or atomically
creates the new session and re-points the lock. Concurrent starts contend on the one pointer,
so the loser's transaction retries, sees the now-set pointer, and joins instead of duplicating.
The pointer self-heals (checks the pointed session's status) so no clear-on-finish is needed,
and it carries no status/completedAt so it's invisible to the active/history queries.
GameSessionManager routes all 7 games through it. firestore.rules adds member-write for
sessions/_active (deployed).

Verified live on both emulators: atomic create → 1 session + pointer; sequential 2nd start →
joins (1 session); literal parallel-tap race → 1 session (was 2); 0 FATAL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 21:43:06 -05:00
..
schemas fix: use sex column for Desire Sync question filtering instead of fragile ID pattern 2026-06-18 00:32:39 -05:00
src fix(games): atomic session start to prevent duplicate sessions on concurrent start (F-RACE-001) 2026-06-25 21:43:06 -05:00
build.gradle.kts brand: loading state, themes, manifest, art preview, pairing screen updates 2026-06-25 15:24:46 -05:00
proguard-rules.pro feat: settings polish, privacy strings, home partner state, proguard rules 2026-06-21 09:49:02 -05:00