112 lines
13 KiB
Markdown
112 lines
13 KiB
Markdown
# Claude QA Coverage Matrix
|
||
|
||
> Resume anchor. Status: `todo | pass | fail(→id) | n/a`. See `ClaudeReport.md` run-state header for current position.
|
||
> **Round 6 (branding + Future.md regression) COMPLETE 2026-06-25, client `f47c8e2`:** new surfaces from `95cad84` (white-keyhole icons, animated chip+fill loader, splash, pairing hero) + `f47c8e2` (inclusive gender, turn copy, push-budget split, results-suppression `ActiveGameSessionMonitor`, paywall retry/offline/hide-Continue, auth rotator). **0 new issues; still 0 open P0–P3.** Live: loader (both themes), splash→handoff, launcher icon, ToT+How Well open (no crash → #4 VM injection sound), paywall purchase screen (friendly error + Try again + Continue hidden, online→generic msg), onboarding illustration. Unit tests green. Gender step / rotator / turn-copy / results-timing / weekly-cap = code+unit-verified (live deferred: fragile multi-text-field & 2-device timing; low risk over proven patterns). Baseline restored (QA re-signed-in via admin token; couple intact).
|
||
> **Round 5 (functions deploy + expanded re-QA) COMPLETE 2026-06-25, client `765916a` + functions DEPLOYED:** E-OBS FIXED+DEPLOYED (12 senders set channelId; chat push → `partner_activity` live) + E-003 results-ready FIXED+DEPLOYED (finished-game → per-session results). **0 open P0–P3.** New Pass G (account creation + fake-account) clean. Varied gameplay (Standard/Deep, 0-match) + nav fuzzing — no new bugs. Baseline restored (couple intact, throwaway deleted, Sam re-paired).
|
||
> _Round 4: E-003 + B-004 (P2) + A-OBS (P3) FIXED + verified live._
|
||
|
||
## Pass G — Account creation, validation & fake-account abuse
|
||
**R5 live:** sign-up flow end-to-end (email/pw/confirm → profile 3 steps → unpaired home) ✓; weak-password → friendly
|
||
"at least 8 characters" error ✓; fresh-account **isolation** (unpaired "Invite my partner", zero couple data) ✓;
|
||
**duplicate-email → `auth/email-already-exists`** rejected ✓; invite code **single-use + 24h expiry** shown, **bogus
|
||
code "ZZZ-ZZZ" → "Invite not found."** rejected (friendly, not paired) ✓; **recovery phrase** client-generated ✓;
|
||
sign-out → onboarding carousel → debug-token restore ✓. **No security findings.** (Rules-level non-member READ denial:
|
||
covered by app-level isolation + static member-scoped rules audit; live crafted-request blocked by App Check.)
|
||
|
||
## Pass A — Couple-shared premium (states: neither / partner-only / self)
|
||
| Feature | neither→locked | partner→both unlock | self→unlock | Status |
|
||
|---|---|---|---|---|
|
||
| Chat media + reactions | pass | pass | pass | pass (couple-shared) |
|
||
| Play: Desire Sync | pass | **fail→A-001** | pass | fail→A-001 |
|
||
| Play: Memory Lane | pass | **fail→A-001** | pass | fail→A-001 |
|
||
| Play: Connection Challenges | pass | fail→A-001 | pass | fail→A-001 |
|
||
| Question Packs (premium) | pass | fail→A-001 | pass | fail→A-001 |
|
||
| Wheel: Category Picker / Spin / History | pass | fail→A-001 | pass | fail→A-001 |
|
||
| Date Match / Plan Date | pass | fail→A-001 | pass | fail→A-001 |
|
||
| Subscription screen (own status) | n/a | n/a | n/a | pass (by-design per-user) |
|
||
|
||
Pass A: **complete** (1 systemic P1). **A-001 FIXED** (e8892a9) — couple-shared everywhere; re-verify each feature in re-QA. New cosmetic A-003 (P3, badge). Subscription screen by-design.
|
||
**R3 re-verified LIVE (2026-06-25):** neither→paywall ("Go deeper together"), partner→couple-shared unlock (Sam free entered Desire Sync + Memory Lane), self→unlock; A-003 badges hidden under premium / shown when free (count 0↔2). New A-OBS (P3): paywall plan-load shows raw "credentials issue" error (env: no RevenueCat sandbox).
|
||
|
||
## Pass B — Games lifecycle (start / play / finish + results)
|
||
**RESTARTED 2026-06-24 (R2-B2): full re-run from game #1 with the PLAY-AS-THE-USER mindset** (navigate only via the
|
||
real in-app path; report-first-then-workaround on any broken flow). Prior R2 This or That / How Well passes are
|
||
superseded — redo every game cleanly. (Prior result for reference: This or That 5/5 ✅, How Well 5/5 ✅.)
|
||
**✅ R2-B2 COMPLETE — all 7 games played one full time through on both devices via real user nav; gameplay all PASS.**
|
||
Findings surfaced by playing-as-user: **B-001 (P1)** finished session never closes → blocks next game; **C-NAV-001 (P1)**
|
||
back from Home resurfaces onboarding/auth; **B-002 (P2)** Home "Play now" → generic hub; **C-CC-001 (P2)** Connection
|
||
Challenges dup header/double-back; **C-DS-001 (P2)** Desire Sync dark-mode low contrast; **B-003 (P3)** confusing Desire
|
||
Sync counts. Sam reverted to free (baseline). `date_match` push verified live (Pass E bonus).
|
||
|
||
| Game | starts | plays | finishes/results | no crash | Status |
|
||
|---|---|---|---|---|---|
|
||
| 1. This or That | pass | **pass (full, user-nav)** | **pass** | pass | **R2-B2: 5/5 via Play hub, answers synced, results match both (4/5 "Two peas in a pod", Q2 Differ correct), no crash ✅. Session-lifecycle bug B-001 (P1) hit on exit.** |
|
||
| 2. How Well Do You Know Me | pass | **pass (full, user-nav)** | **pass** | pass | **R2-B2: QA answered 5 (incl. a 1-5 scale Q5); Sam predicted via Play hub — 3 correct + 1 deliberate miss (Kind tone vs Specific examples) + scale match → results show 4/5 "You really know each other" with the wrong one marked ✗ on BOTH devices, scoring accurate, no crash ✅** |
|
||
| 3. Desire Sync | pass | **pass (full, user-nav)** | **pass** | pass | **R2-B2: QA(free) entered w/o paywall (A-001 live ✅); both answered 5 Yes/No → exactly 3 mutual desires revealed, mismatches hidden (privacy correct), results match both, no crash ✅. Findings: B-003 (P3 confusing counts), C-DS-001 (P2 dark-mode low contrast on revealed list).** |
|
||
| 4. Connection Challenges | pass | **pass (day-cycle, user-nav)** | **pass** | pass | **R2-B2: opened (D-001 rules hold ✅); started Gratitude Week → both completed Day 1 → day ✓, 🔥1 streak, advanced to Day 2 "Both of you showed up today", synced on both, no crash ✅. (7-day series is time-gated; full per-day cycle verified.) Finding: C-CC-001 (P2 duplicate header + double back). Minor: first partner's view shows next-day content + "waiting for partner" before the day is mutually done (self-resolves).** |
|
||
| 5. Memory Lane | pass | **pass (create+seal, user-nav)** | **pass (sealed)** | pass | **R2-B2: loads clean (D-001 ✅, no hung heart); QA wrote a capsule (title+body), picked "1 month" → sealed "Opens in 29 days"; **encrypted at rest** (title+content `enc:v1:`, `unlockAt`=+30d, status=sealed); Sam sees the same sealed capsule cross-device; no crash / no PERMISSION_DENIED ✅. Unlock/reveal is future-dated (can't test w/o time-travel). Single header (no C-CC-001 here).** |
|
||
| 6. Spin the Wheel | pass | **pass (full, user-nav)** | **pass** | pass | **R2-B2: QA(free) entered (A-001 ✅); spun → "Date Night" category → both answered all 10 prompts (multi-select) → reveal "Here's how you each answered" with per-Q You/partner breakdown matching on BOTH devices, no crash ✅. Wheel session synced (Sam joined QA's active session). Dark answer text a bit dim (C-OBS pattern, readable).** |
|
||
| 7. Date Match | pass | **pass (full, user-nav)** | **pass** | pass | **R2-B2: QA(free) entered (A-001 ✅, in Play hub below Question Packs); both swiped date-idea deck (❌/⭐/💗); QA + Sam both liked the same 3 → 3 `date_matches` created (sunrise_hike/kayak/rock_climbing); Sam got "It is a match!" modal + LIVE "It's a match!" push notification; "Your Matches" shows all 3 "Mutual love"; no crash / no PERMISSION_DENIED ✅. (Premium-badged ideas accessible via couple premium.)** |
|
||
|
||
_Note: stale active session blocked games (B-001); cleared via in-app "End their game" (recovery verified). Exit each game via Back to Play between games so the session closes._
|
||
**REQUIREMENT (updated): each game must be played ONE COMPLETE time through on both devices (every step → finish/
|
||
reveal/results), not just launched.** All rows above are currently `launch ok / partial` only → **full playthrough
|
||
still owed for every game** in Round 2 (premium games need a premium toggle). A launch-only row counts as `partial`, not `pass`.
|
||
|
||
## Pass C — Visual (light + dark), all ~50 routes
|
||
**R3 (2026-06-25):** ~14 screen-types swept in Dark (5554), several in Light (5556 during A/B) — all render clean,
|
||
readable, no FATAL, no new dark-mode contrast issues; **0 `enc:v1:` leaked to conversation UI**. Covered: Home, Play
|
||
hub, all 7 game screens (setup/play/reveal), Paywall, Settings (+Subscription +Appearance), Today/daily-question
|
||
(+answer detail), Messages inbox, Conversation (image+voice+text+reaction). C-DS-001 dark-contrast fix holds.
|
||
**Back-stack ✅** deep→hub→Home→launcher clean (no double-back; C-NAV-001 holds). C-OBS resolved (debug menu gated).
|
||
_Deferred (nav-drift; standard list/detail, lower-risk): Question Packs detail, Bucket List, Past Games, Wheel History,
|
||
Answer Reveal (sealed), Date Builder/Plan Date, fresh-account auth/onboarding/pairing._
|
||
|
||
## Pass D — Security & Encryption (D1–D6)
|
||
**R7 DEEP DIVE (multi-angle, 2026-06-25):** **D1 at-rest — CLEAN (admin ground-truth read):** messages `text` +
|
||
`lastMessagePreview`, all 4 game-answer collections (`this_or_that`/`how_well`/`desire_sync`/`wheel`, both users),
|
||
capsule title+content, `date_swipes.actions` = `enc:v1:`; `wrappedCoupleKey` = ciphertext (recovery-phrase-wrapped,
|
||
**argon2id**); `encryptedRecoveryPhrase` server-blind + **wiped on acceptance** (confirmed absent on accepted invite);
|
||
plaintext `inviteCode` **not exploitable** (no code-encrypted secret persists; `/invites/{code}` readable only by
|
||
inviter). **D3 raw-API negative (LIVE, executed — no longer deferred):** non-member ID token (Identity Toolkit
|
||
`signInWithCustomToken`) → Firestore REST on couple doc/conversation/messages/answers/session/capsules/partner-profile
|
||
= **all `403 PERMISSION_DENIED`**; non-member writes (couple doc, partner entitlement, **real path
|
||
`users/{uid}/entitlements/premium`**) = **all `403` → no self-grant**. Member token reads `200` (characterizes layer:
|
||
**App Check not enforced on Firestore — rules are the sole gate, and they hold**). Only writable = cosmetic own-doc
|
||
fields (`plan`) that **no gate reads**. **No P0/P1 security findings.** Two hardening notes → `Future.md`.
|
||
|
||
|
||
**R3:** D2 deployed rules re-audited ✅ (B-001 sessions + D-001 capsules/challenges fixes present; hasPremium +
|
||
entitlements server-only; ciphertext enforced; no catch-all). D1 at-rest ✅ (chat text + lastMessagePreview =
|
||
`enc:v1:`; how_well answers + capsules = `enc:v1:`). D4/D5/D6 unchanged since R1 (code identical) → hold.
|
||
**D3 live non-member: deferred** (needs a 3rd fresh account; only 2 emulators, both couple members; rule logic
|
||
statically member-scoped). No P0/P1 security findings.
|
||
|
||
## Pass E — Notifications (17 types × {foreground, background, killed} + tap-to-open)
|
||
**R6 live (games + messages, 2026-06-25, build `f47c8e2`):** full live two-device run.
|
||
- **chat_message** ✅ end-to-end: Sam→QA (QA bg) posts on **channel=partner_activity**, title "Sam sent a message"
|
||
(partner name, not private), body "Tap to read and reply." — **message text NOT in payload** (privacy holds);
|
||
small icon = white monochrome mark; tap→**main conversation with content** (verified via the exact intent —
|
||
shade-tap is flaky in the adb harness, lands on launcher, but the contentIntent routing is sound).
|
||
- **partner_started_game** ✅: QA started This or That → Sam (bg) posts on **channel=game_activity**, "QA is playing /
|
||
QA has started a game. Tap to join!" (content-free); tap→**joins the active session** (same 1/5 prompt).
|
||
- **partner_finished_game / results** ✅: both finished → **results push DELIVERED to backgrounded QA** (Round 5
|
||
couldn't confirm this live) on **channel=game_activity**, "Sam finished the game / Sam finished — tap to see your
|
||
results!" (content-free); tap→**per-session This or That results** (5/5), per E-003.
|
||
- **#4 results-suppression** ✅: Sam stayed foreground on the session throughout → received **0** notifications
|
||
(the partner_completed_part + partner_finished_game pushes to Sam were suppressed by ActiveGameSessionMonitor),
|
||
while backgrounded QA got the results push. Clean confirmation of both delivery + suppression.
|
||
- No FATAL either device; baseline tidy (0 active sessions, couple intact). **No issues found.**
|
||
|
||
|
||
**R3 live:** FCM tokens valid for both. **chat_message ✅ full chain** (bg deliver + content-free + tap→exact
|
||
conversation w/ content). **partner_started_game**: bg deliver + content-free ✅; tap→Play hub (not the game) =
|
||
**E-003 (P2)**. **E-OBS (P3)**: bg pushes use fcm_fallback channel. date_match live-verified R2-B2. E-001/E-002 fixes
|
||
present in code. Full 17×{fg/bg/killed} matrix not exhaustively run; routing centralized + code-verified for the rest.
|
||
|
||
## Pass F — Resilience / lifecycle / concurrency / time
|
||
**R3:** offline (airplane mode) → Today renders from cache, no crash ✅; rotation/config-change → landscape renders,
|
||
state preserved, no crash ✅; process-death/restore → ~6 cold restarts all clean to Home (auth persists) ✅;
|
||
concurrency → both devices played games simultaneously, sessions synced + B-001 auto-complete on concurrent finish ✅.
|
||
Time-gated content (capsule "Opens in 29 days", challenge day-gating) can't be time-traveled — noted.
|