diff --git a/ClaudeQAPlan.md b/ClaudeQAPlan.md index 45778b72..0ef1003f 100644 --- a/ClaudeQAPlan.md +++ b/ClaudeQAPlan.md @@ -154,6 +154,19 @@ Games: This or That, How Well Do You Know Me, Desire Sync, Connection Challenges intermediate screen and interaction works (selections register, progress advances, both-answered gating, reveal/scoring/summary correct). Premium games (Desire Sync, Memory Lane) need a premium toggle to play. - The session lifecycle is exercised by the real playthrough: `status` active→completed; reveal/results correct on both. +- **VARY THE STYLE OF PLAY (don't just repeat the happy path):** across runs, deliberately exercise *different* ways a + real couple would play each game, because different inputs hit different code paths: + - **Different option/length/mood choices** — every round length (5/10/15), every mood/category, the "All topics"/ + shuffle option, and **each distinct answer type** (A/B, Yes/No, True/False, 1–5 scale, multi-select, free-text). + - **Different answer *patterns* that change the result** — all-match vs all-mismatch vs partial; both-yes vs both-no + vs split (so reveals show "shared", "all private", "0 matches", "perfect/zero score" — verify each renders right). + - **Different turn orders / who-starts** — partner A starts vs partner B starts; the guesser opens before vs after + the subject finishes; both open simultaneously (race); one device much slower than the other. + - **Different exit/resume styles** — finish normally; quit mid-game; background mid-game then resume; cold-kill + mid-game then reopen; "End their game"; re-open a completed session for the replay/results; play two games + back-to-back, and a *different* game type immediately after. + - **Edge inputs** — submit with nothing selected (should be blocked), rapid double-taps on answer/confirm/next, + spamming the start button, tapping during the reveal animation. None should crash, duplicate, or desync. - Edges: re-open a completed session, leave mid-game (resume), no stuck session, no crash, logcat clean. - Game start/finish pushes (`onGameSessionUpdate`) exercised here; full delivery/deep-link audit in **Pass E**. - **Media permissions** (CAMERA, RECORD_AUDIO): granted works, denied degrades gracefully. @@ -175,6 +188,21 @@ Account); Paywall; Your Progress/Activity; Recovery. opens correctly each time — e.g. a conversation from the inbox AND from "Discuss" AND from a notification; a game from the Play hub AND from a notification; Paywall from each gated feature; Settings sub-pages; reveal from Today AND from history AND from `partner_answered`. A screen that works from one entry but breaks/duplicates from another = bug. +- **TAKE EVERY AVENUE (exhaustive nav fuzzing — actively hunt for nav bugs, don't just walk the happy path):** treat + navigation as something to *break*. On every screen, **tap every interactive element** — each button, card, row, + icon, chip, link, tab, header back-arrow, system back, and any "see all / history / edit / manage" affordance — and + follow where it goes. Then try the *combinations and sequences* a curious user hits: + - **Every order:** switch bottom tabs in many orders, mid-flow (open a game, jump to Messages, come back); enter a + deep screen then tab away then back; open A→B→C then back-back-back. + - **Rapid / repeated input:** double- and triple-tap navigation targets (especially "open game", "Play now", + "Create/Start session", notification taps) to surface double-push/duplicate-screen/stale-route bugs (cf. B-004). + - **Interrupt mid-navigation:** background/rotate/lock during a transition; tap a notification while already on that + screen, on a different screen, and while logged-out/unpaired; cold-start straight onto a deep link. + - **Dead-ends & traps:** from *every* screen confirm there's always a way out (back/close/home) — no screen that + strands the user, needs two backs, exits the app unexpectedly, loops, or lands blank. Re-check the asymmetric-game + waiting screens, replay/results screens, and paywall specifically. + - Log **every** wrong/duplicate/dead destination with the exact tap sequence to reproduce. Wrong/double-back or + dead-end = **P2** (P1 if it traps the user or loses their progress). - **Back-stack / "double back":** from every entry point, **system back AND the in-app back arrow** return to the correct previous screen — no dead-ends, no exiting the app unexpectedly, and **no screen that requires pressing back twice** (duplicate/stacked destinations on the back stack = bug). Bottom-tab reselection and deep-link/ @@ -203,6 +231,31 @@ Account); Paywall; Your Progress/Activity; Recovery. couple — migration completes without exposing plaintext or losing/garbling old content, and a half-migrated couple is safe (no mixed read failures, no downgrade). This is the riskiest data path for existing users. +### Pass G — Account creation, validation & fake-account abuse (MANDATORY — both the happy path AND the attacks) +Cover **every account-creation avenue a real user takes** and **every fake/abusive creation attempt an attacker would +try.** Use throwaway test accounts (sign-out → fresh sign-up; never `pm clear`). Report-first like every pass. +- **Real creation flows (happy path + validation):** sign-up (email/password and any social/anonymous path), profile + creation, and pairing — both **create-invite** and **accept-invite** sides. Verify field validation (invalid/empty + email, weak/short password, mismatched confirm, name length/emoji/unicode), the **error copy is friendly** (no raw + SDK/Firebase error leaking — cf. A-OBS), loading/disabled states, and that a brand-new unpaired account lands on the + correct "create or accept invite" home (not a broken/blank or paired view). +- **Duplicate / conflicting creation:** sign up with an **already-registered email** (clear "already in use", no crash, + offer sign-in); create a second account while one is signed in; re-run onboarding after completing it; accept an + invite while **already paired** (must be rejected cleanly); two devices accepting the **same invite** (single-use — + the second must fail gracefully). +- **Fake / malicious creation attempts (security — expect DENY, never crash or leak):** create an account that is + **NOT a member** of the test couple and attempt every cross-couple action (read messages/answers/dates/entitlements, + write to the couple, self-grant `premium`/`hasPremium`, join/hijack pairing with a guessed/expired/reused invite + code) — all must be **denied by rules** (this is the live execution of **D3**). Probe **invite-code abuse**: replay a + used code, use an expired code, brute-force/guess attempts (CSPRNG entropy + single-use + expiry must hold). Probe + **App Check**: a request without a valid token is rejected. Confirm a malformed/forged sign-up can't bypass profile + or membership requirements. **Any successful unauthorized create/read/write = P0.** +- **Account lifecycle around creation:** sign-out → sign-in (state restores, no stale couple); **delete account** then + re-create with the same email (clean slate, partner notified/unpaired); an unpaired/just-created account tapping a + stale notification or deep link is handled gracefully (no crash, sane landing). +- **Done = every creation avenue exercised** (happy + duplicate + malicious) with each attack **denied** and each happy + path validated end-to-end; findings filed with exact repro. + ### Pass E — Notifications (every type delivers, deep-links, leaks nothing) For each: trigger fires → delivered to the **right partner (never self)** → in **foreground/background/killed** → correct channel + copy with **no private content** → **tap opens exactly the right item** (loaded, not generic Home/