# Claude QA Report — Full-App QA (living report) > **RUN-STATE: Round 1 | Pass C (visual light+dark) NEXT | NEXT ACTION: enumerate AppRoute screens, 5554=Dark/5556=Light, screenshot each.** (Pass A done: A-001 P1. Pass B sweep done: B-001 P3; full game lifecycle partial.) > Playbook: `ClaudeQAPlan.md`. Coverage matrix: `ClaudeQACoverage.md`. Report-only during passes (no fixes until the fix phase). > Devices: emulator-5554 (QA=`Y05AKO`) + emulator-5556 (Sam=`imDjjO`), paired (coupleId `Xal3Kw3gjSdn0niERYKJ`). Build == HEAD `64f0a7e`. _(Prior games/notifications QA from 2026-06-24 was completed + verified; superseded by this full-app effort.)_ --- ## Severity summary (Round 1) | Severity | Open | Fixed | |---|---|---| | P0 | 0 | 0 | | P1 | 1 | 0 | | P2 | 0 | 0 | | P3 | 1 | 0 | --- ## Pass A — Couple-shared premium ✅ pass complete **Target:** if either partner is premium, all premium features unlock for both. **Result:** only chat is couple-shared. Every other feature gate is per-user → a free user whose partner paid stays locked. | ID | Area | Screen/Route | Severity | Description | Repro | Status | |---|---|---|---|---|---|---| | A-001 | Premium gating | PlayHubViewModel, DesireSyncScreen, MemoryLaneScreen, ConnectionChallengesScreen, QuestionPackLibraryViewModel, wheel CategoryPicker/SpinWheel/WheelHistory(VMs) | **P1** | These gate on per-user `EntitlementChecker.isPremium()` instead of couple-shared `CouplePremiumChecker.coupleHasPremium(partnerId)`. A free partner of a premium user stays locked — violates couple-shared requirement. | Set Sam premium, QA free → QA Play hub still shows 🔒 Premium on Desire Sync + Memory Lane (confirmed live). Code: only `ConversationViewModel` uses CouplePremiumChecker. | Open | | A-002 | Premium (control) | ConversationViewModel (chat) | — | **Working correctly** (couple-shared) — kept as the reference pattern for the A-001 fix. | Verified prior round: partner-premium unlocks chat media/reactions for the free partner. | OK | **Note (by-design, not a bug):** `SubscriptionScreen` uses per-user `isPremium()` — correct, it reflects the user's *own* subscription/account state, not a feature gate. ## Pass B — Games lifecycle (launch/crash sweep done; full two-device lifecycle partial) | ID | Area | Screen/Route | Severity | Description | Repro | Status | |---|---|---|---|---|---|---| | B-001 | Games / sessions | couples/{id}/sessions | **P3** (observe) | A stale `active` wheel session (startedBy QA, `createdAt` missing/undefined) blocked **all** games ("Waiting for Sam"). In-app **"End their game" recovery works** (session→completed, games unblocked). Likely a prior-test artifact, but: sessions appearing without a timestamp + one stale session blocking every game is worth a guard. | Open This or That → "Waiting for Sam… Sam is playing a Wheel game"; tap End their game → unblocked. | Open | **Launch/crash sweep (QA, free):** This or That ✅ (mood/length select), How Well Do You Know Me ✅ (intro), Connection Challenges ✅, Spin the Wheel ✅ — all render, **no FATAL**. Desire Sync + Memory Lane are premium-gated (covered in Pass A; gameplay needs premium toggle). Date Match: todo. Full two-device start→finish + results not exhaustively re-run this round (the prior round verified `onGameSessionUpdate` start/finish end-to-end). ## Pass C — Visual (light + dark) _not started_ ## Pass D — Security & Encryption _not started_ ## Pass E — Notifications _not started_