Commit Graph

30 Commits

Author SHA1 Message Date
null 9c84c36443 fix(qa): R10 fix phase — 5 P2 bugs fixed (C-HOME-001, C-NAV-002, C-NAV-003, C-PW-001, C-SEC-001) 2026-06-27 10:34:26 -05:00
null 32b5b560a2 docs(qa): update report with R10 results — E-GAME-002 fix, foreground banner, C-SEC-001 2026-06-26 20:04:20 -05:00
null 5ba5b4a8ec qa(R9): clean confirmation round — deferred Pass C + Pass F network swept, 0 new findings
Confirmed + pruned I-001/I-002 (0 outcomes denials/CCE on fixed build). Deferred Pass C
deep/list screens swept (Answer History, Together/Activity, Bucket List, Date Match,
Date Matches in dark; Home/Privacy&Terms light parity) — clean, no clipping/contrast/
FATAL. Pass F network: airplane-mode -> cache render no crash; reconnect -> recovers.
Baseline restored (0 sessions, 0 outcomes). FLAWLESS bar: 0 open P0-P2 (1 P3 J-OBS).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 08:42:03 -05:00
null dbf8a6f18e qa(R8): wrap — Pass E new-type status (not implemented), couple-premium-unlock idea to Future.md
Code check: the speculative Pass E types added by the merged playbook (join_game,
partner_joined_game, game_ended, date_plan_update, subscription_entitlement_changed,
...) are not implemented (0 files) -> marked not implemented -> Future.md. Logged the
worthwhile ones to Future.md ## QA (notify free partner on couple premium unlock; join/
end pushes). Round 8 at the flawless bar: 0 open P0-P2 (1 P3 J-OBS); I-001/I-002 fixed+
verified pending Round 9 confirm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 00:00:31 -05:00
null ab29f6b12f fix(outcomes): restore Your Progress read — scope query to allowed dayKeys + coerce Long scores (I-001, I-002)
I-001: getOutcomes() did a bare collection list .get() on couples/{cid}/outcomes,
which firestore.rules denies (reads allowed only for dayKey in day_0/30/60/90) ->
always PERMISSION_DENIED, swallowed to emptyList(). Now scopes the query with
whereIn(FieldPath.documentId(), OUTCOME_DAY_KEYS) so it satisfies the rule.

I-002 (found while fixing I-001): toOutcomeScores() cast values to Map<String,Int>,
but Firestore returns integer fields as Long on Android -> ClassCastException ->
scores dropped (same shape submitOutcomeCallable writes, so the real path was broken
too). Now coerces (value as? Number)?.toInt().

Verified live: 0 outcomes PERMISSION_DENIED after relaunch; seeded a day_0 baseline
(int64) -> "Your Progress" shows "Baseline recorded" (was "No baseline yet"). Seed
removed, couple baseline restored (0 outcomes, 0 active sessions). Both pending one
re-QA confirmation round before pruning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:58:37 -05:00
null 35d36e6851 qa(R8): Pass J accessibility — font scale 2.0 usable, semantics clean, reduce-motion honored
font_scale 2.0: Home/Paywall/Settings reflow+scroll, no clipped/hidden buttons (only
ellipsis + nav-label wrap). Semantics: 0 unlabeled Icon(), 111 decorative null'd,
meaningful labels on key controls, loader has "Loading…". Reduce-motion honored in 7
surfaces, no hang/crash. Touch targets mostly 48dp. Finding J-OBS (P3): a few
conversation icon-buttons ~42-45dp wide. No P0/P1/P2 a11y blockers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:47:27 -05:00
null f740b1d9a1 qa(R8): Pass I performance — route smoke checklist + I-001 (P1) outcomes read denied
Cold start 1253ms; core tabs 6.3% janky; conversation/Play-hub scroll ~36ms 90th;
no window/Activity/listener leak (meminfo stable over open/close x6); lazy-load (17),
Coil (11), Room caching all in place. Found I-001 (P1): FirestoreOutcomeDataSource
.getOutcomes() does a bare collection list .get() that firestore.rules:658 denies
(reads allowed only for dayKey in day_0/30/60/90) -> always PERMISSION_DENIED, swallowed
to emptyList() -> "Your Progress" never shows recorded outcomes + re-prompts done days.
Fix (fix phase): whereIn(documentId, [day_0..90]).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:41:08 -05:00
null 11208c6fb5 qa(R8): re-confirm F-RACE-001 live (race -> 1 session, loser joins same set) + prune
Round 8 chunk 1. Simultaneous mood-tap on both emulators -> exactly 1 active session
(was 2 pre-fix); race-loser hit WaitingForPartner -> "Join the game" -> joined the
winner's session at the same Q1 (shared reveal preserved). Regression smoke clean:
no FATAL, game opens both devices, inbox loads, messages + date_swipes ciphertext at
rest. F-RACE-001 pruned to the archived-ID line per report hygiene; 0 open P0-P3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:32:31 -05:00
null 96987bf29a docs(qa): merge notification-suite playbook, add report hygiene + finding-routing, clean report/coverage
- ClaudeQAPlan.md: fold the deep notification + join-game suite into Pass E (both-client
  matrix, 6 assertions, expanded inventory, game/join-game suites, payload security,
  malformed/stale tests); add Pass B join-paths + Pass C routes-into-games; add missing
  batch rows G/H; add Report-hygiene (one-confirmation-round prune) + coverage-matrix
  hygiene + easy-to-read mandate; add "Where every finding goes" routing table.
- ClaudeReport.md: collapse stacked R1-R7 run-states + fixed tables to current-state
  (0 open P0-P3; F-RACE-001 pending one confirm; older fixed IDs archived).
- ClaudeQACoverage.md: current-status matrix (flip stale fail->A-001 to pass, drop
  contradictory Pass B footer, add status-at-a-glance, surface todo/deferred).
- removed stray seed/questions/Claude_QA_Playbook_Full_App_QA_Notifications_Merged.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:23:30 -05:00
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
null 4686a2c200 docs(seed): replace question guides with v2 — content guide, rewrite plan, new quality checklist 2026-06-25 18:48:37 -05:00
null 83d3d59903 qa(r5): functions deployed (E-OBS + E-003 results-ready) + expanded re-QA — 0 open P0-P3
E-OBS FIXED+DEPLOYED: all 12 FCM senders set android channelId; backgrounded chat push verified on
partner_activity (was fcm_fallback). E-003 results-ready FIXED+DEPLOYED: finished-game deep-link ->
per-session results screen (verified). New Pass G (account creation + fake-account abuse) CLEAN:
sign-up/validation, isolation, duplicate-email rejected, invite single-use/expiry + bogus-code
rejected, recovery phrase client-gen. Varied gameplay (Standard/Deep 0-match) + nav fuzzing: no new
bugs. Severity board: 0 open at all levels. Baseline restored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 13:12:40 -05:00
null ee19ef3f59 qa(r4): fix phase + re-QA complete — E-003/B-004/A-OBS fixed; 0 open P0-P2
Round 4: the 2 new P2 (E-003 game-push deep-link, B-004 WaitingForPartner Join escape) + 1 new P3
(A-OBS paywall copy) from R3 are fixed, verified live, committed. Regression smoke clean (launch,
This-or-That end-to-end + B-001 auto-close, chat enc:v1 at rest, C-NAV-001 back->launcher).
Only E-OBS (P3) open — bg push channel, needs server change + user-gated functions deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 12:35:49 -05:00
null 0c8586fa9e qa(r3): Round 3 full re-QA (A-F) COMPLETE — 12 fixes hold; 5 new issues logged
Pass F: offline (cache renders, no crash), rotation (state preserved), process-death (~6 clean
restarts), concurrency (simultaneous game play synced) all OK.
RESULT: all 12 prior fixes re-verified holding live; no P0/P1, no security/encryption findings.
New: 2xP2 (B-004 intermittent guesser-stuck; E-003 game notif -> Play hub not the game),
2xP3 (A-OBS paywall copy [env]; E-OBS bg fallback channel); C-OBS resolved (debug menu is gated).
Not yet flawless (2 open P2) -> fix phase + Round 4 re-QA. Baseline restored (both free, 0 active).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 12:35:49 -05:00
null c7140b1e10 qa(r3): Pass A + Pass B fully re-verified live
Pass A: neither->paywall, partner->couple-shared unlock, self->unlock, A-003 badges both
directions. New A-OBS (P3): paywall plan-load shows raw 'credentials issue' (env: no RC sandbox).
Pass B: all 7 game areas played; B-001 holds across 4 async types (auto-complete); B-002 clean
case works; B-003 + C-DS-001 hold; Date Match deck + Wheel + How Well + Desire Sync + ToT all PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 12:35:49 -05:00
null 4e49b92be2 qa(round2-B2): Date Match PASS (3 mutual matches + live It's-a-match push + Matches view); PASS B COMPLETE all 7 games; Sam reverted to free 2026-06-24 23:31:18 -05:00
null 01feee8321 qa(round2-B2): Spin the Wheel PASS (free partner enters; spin->Date Night->both answer 10->reveal matches both, no crash) 2026-06-24 23:22:25 -05:00
null f79b38c07c qa(round2-B2): Memory Lane PASS (capsule create+seal, encrypted at rest enc:v1:, cross-device sealed view, no crash); D1 capsule ciphertext verified live 2026-06-24 23:15:23 -05:00
null 1303597d4a qa(round2-B2): Connection Challenges PASS (day-cycle synced both, streak ok, no crash); C-CC-001 P2 (duplicate header + double back) 2026-06-24 23:03:15 -05:00
null c71d858283 qa(round2-B2): Desire Sync PASS (free partner enters via A-001; 3 mutual desires revealed correctly, mismatches hidden, results match); B-003 P3 (confusing counts), C-DS-001 P2 (dark contrast) 2026-06-24 22:57:50 -05:00
null 3c9037d8e4 qa(round2-B2): How Well PASS (user-nav, predicted 4/5 w/ deliberate miss + scale, results match both, no crash); B-001 re-corroborated (Back to Play leaves session active) 2026-06-24 22:50:59 -05:00
null f8dc8119cb qa(round2-B2): This or That PASS (user-nav, 5/5, results match); B-001 escalated P3->P1 (Back to Play doesn't close finished session -> blocks next game); B-002 P2 (Play now lands on hub) 2026-06-24 22:42:18 -05:00
null 8fa922fb70 qa(round2): RESTART Pass B from game #1 (play-as-user) — coverage reset, build reinstalled both devices 2026-06-24 22:30:09 -05:00
null f9c6e42d92 qa(round2): Pass B — How Well full two-device playthrough PASS (5/5 predict, results match both) 2026-06-24 22:22:48 -05:00
null 693ecd28ef qa(round2): Pass B — This or That full two-device playthrough PASS (5/5, results match both, no crash) 2026-06-24 22:10:15 -05:00
null 99f0ae0c49 docs(qa): Pass C also checks navigation from every entry point + back-stack/double-back
UI review now verifies each screen opens correctly from ALL its entry points (inbox/Discuss/
notification, Play/notification, paywall from each gate) and that back (system + in-app)
returns correctly with no dead-ends, exit-app surprises, or two-back/duplicate-stack issues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:26:23 -05:00
null f121eab67f docs(qa): require a full one-time playthrough of each game (not just launch)
Pass B now mandates playing each game end-to-end on both devices (start -> every step ->
finish/reveal/results); launch-only = partial. Reflected in playbook, report run-state,
and coverage (full playthroughs owed in Round 2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:24:08 -05:00
null 58208fd443 qa(round1): A-001 fixed+verified (couple-shared premium); A-003 P3 logged (static badge)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:53:39 -05:00
null c54ceb16c3 qa(round1): Pass B games launch sweep — no crashes; stale session recovery verified (B-001 P3)
This or That / How Well / Connection Challenges / Spin the Wheel launch clean (no FATAL).
A stale active wheel session blocked all games; in-app 'End their game' recovery works.
Full two-device lifecycle partial this round. Report-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:04:54 -05:00
null 452aaf787a qa(round1): Pass A complete — couple-shared premium gap (A-001, P1)
Only chat uses CouplePremiumChecker; all other gates are per-user → a free partner of a
premium user stays locked. Confirmed live (Sam premium, QA still locked on Desire Sync +
Memory Lane). Report-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 19:59:04 -05:00