docs(qa): point Report + Coverage at Engineering Reference Manual (landmines section)
This commit is contained in:
parent
58d09ac8d3
commit
9eee3951e9
|
|
@ -1,17 +1,19 @@
|
|||
# Claude QA Coverage Matrix
|
||||
|
||||
> **Resume anchor — current status only.** Statuses: `pass | fail→id | todo | n/a | not implemented→Future.md | blocked→id`.
|
||||
> Build `32b5b56` + R10 working-tree fixes (5×P2). Position + verdict: see `ClaudeReport.md` run-state. **Verdict: R10 FULL run A–J + fix phase COMPLETE. 0 open P0–P2; 1 P3 (J-OBS). 5 P2 found+fixed+verified-live this round (pending 1 confirm). E-GAME-002 confirmed+pruned. Security D1–D7 clean.**
|
||||
> Build `2cd0af6` + R11 working-tree art fixes (Theme/BrandIllustration/EmptyState). Position + verdict: see `ClaudeReport.md` run-state. **Verdict: R11 confirmation round COMPLETE — FLAWLESS. 0 open P0–P2. Fixed C-DARKART-001 (P2, dark art follows in-app theme) + C-ART-EDGE-001 (P3, feathered edges), verified live both decoupled theme directions. 5 R10 P2 fixes re-confirmed + pruned. Entrypoint smoke 6/6 green. Only open: J-OBS (P3 touch targets) + 2 freshly-fixed art items pending 1 confirm.**
|
||||
>
|
||||
> **📖 Architecture reference:** see [`docs/Engineering_Reference_Manual.md`](docs/Engineering_Reference_Manual.md) — contains architecture, security model, data model, and the [Known landmines](docs/Engineering_Reference_Manual.md#known-landmines-and-recent-fixes) section that backs every fix-and-pruned ID below.
|
||||
> Hygiene: this is a *current-status* matrix, not a per-round changelog — `fail→id` flips to `pass` once a fix is
|
||||
> confirmed (ID archived below); finished rounds collapse to the history line. (See Report hygiene in `ClaudeQAPlan.md`.)
|
||||
|
||||
## Status at a glance
|
||||
| Pass | Coverage | Status |
|
||||
|---|---|---|
|
||||
| A — Couple-shared premium | all gated features × neither/partner/self | ✅ pass |
|
||||
| B — Games lifecycle | all 7 games played full, 2-device, real user-nav | ✅ pass |
|
||||
| C — Visual (light+dark) | R10 re-sweep: Messages/conv/thread, Today, Paywall, Wheel History, Activity, Home, wheel back-stack | ⚠️ 5 P2 open (C-HOME-001 dup card · C-NAV-002 wheel back-stack · C-NAV-003 dbl header · C-PW-001 dark paywall · C-SEC-001 recovery) |
|
||||
| D — Security & encryption | R10: D1 at-rest · D2 rules (incl secure-subdoc gate) · D3 live raw-API · D4 recovery · D5/D6/D7 | ✅ clean (C-SEC-001 = UI wrong-store, not crypto) |
|
||||
| A — Couple-shared premium | R12: code audit (all gates→CouplePremiumChecker) + live couple-shared unlock (Sam prem→QA free unlocks Desire Sync setup + Memory Lane badge) | ⚠️ 1 P1 (A-201 Date Match premium ideas ungated — free user liked a ★Premium idea, no paywall); all other gates couple-shared ✅ |
|
||||
| B — Games lifecycle | R12: 4 async games full 2-device end-to-end (ToT Light×5, Wheel mixed-types, How Well asym, Desire Sync shared/private) + start/join/first-finisher/finish/results/back-stack; CC+MemoryLane+DateMatch render/core (full per R10) | ✅ pass (first-finisher nudge + C-NAV-002 + Ready=Start re-verified live; MemoryLane title/preview run-on → Future.md) |
|
||||
| C — Visual (light+dark) | R12: Messages(inbox+conv) both themes, Today, Subscription + organic A/B sweep (Home/Play/all game screens/Security/MemoryLane/DateMatch/Paywall) + R11 decoupled-theme art; back-stack spot-checks OK | ✅ regression-clean vs R10 full sweep · NEW **C-ART-EDGE-002 (P3)** direct-call hero art (daily-question, couple_subscription, etc.) hard edges on dark · C-DARKART-001+C-ART-EDGE-001 (shared helpers) hold |
|
||||
| D — Security & encryption | R12 LIVE: D1 (4 game collections enc:v1:) · D3 raw-API non-member 403×4 + member-scoped + messages not enumerable · D5 self-grant premium PATCH→403; D2/D4/D6/D7 carried R7/R10 (rules unchanged, no deploy) | ✅ clean — cornerstone holds; bounds A-201 (server blocks real premium self-grant) |
|
||||
| E — Notifications | R10 live: E-GAME-002 confirmed (start push+banner+Join), finish/answer/reveal pushes | ✅ pass · E-GAME-002 pruned · full fg/bg/killed matrix **partial** |
|
||||
| F — Resilience | R10: concurrency double-start→1 session · process-death→clean+FCM re-register · offline(R9) | ✅ pass · time-travel + deletion-cascade deferred |
|
||||
| G — Account creation / fake-account | R10: abuse live via D3 (non-member denied, no self-grant) + invite rules; happy/validation R5-clean (unchanged) | ✅ pass |
|
||||
|
|
@ -112,6 +114,7 @@ Route smoke-test checklist (re-runnable: `dumpsys gfxinfo closer.app reset` →
|
|||
---
|
||||
|
||||
## Round history (one line each)
|
||||
- **R11** — confirmation round, FLAWLESS (0 open P0–P2): fixed C-DARKART-001 (P2, art follows in-app theme via `LocalAppInDarkTheme` + config-overridden context) + C-ART-EDGE-001 (P3, edge feathering) in shared `BrandIllustration`/`EmptyState`, verified live both decoupled theme directions (system-light+app-Dark→dark art · system-dark+app-Light→light art), 0 FATAL; re-confirmed + pruned the 5 R10 P2 fixes (C-HOME-001/C-NAV-002/C-NAV-003/C-PW-001/C-SEC-001); entrypoint smoke 6/6 green on fresh APK (launcher + 5 notif cold-starts open & stay). Art fixes in working tree; rest committed `2cd0af6`.
|
||||
- **R10** — FULL run A–J + fix phase: 5 P2 found+fixed+verified-live (C-HOME-001 dup card · C-NAV-002 wheel back-stack · C-NAV-003 dup app bar · C-PW-001 dark paywall · C-SEC-001 recovery wrong-store); E-GAME-002 confirmed live (start push+banner+Join) & pruned; concurrency double-start→1 session; security D1–D7 clean; perf/a11y no regression. 0 open P0–P2 (5×P2 pending 1 confirm).
|
||||
- **R7** — security/concurrency deep dive (multi-angle): cornerstone clean; F-RACE-001 found+fixed+verified. 0 new open.
|
||||
- **R6** — branding drop + Future.md backlog regression: 0 new open.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
# Claude QA Report — Full-App QA (living report)
|
||||
|
||||
> **Verdict (2026-06-26): R10 FULL ClaudeQAPlan run COMPLETE (A–J + fix phase). 0 open P0–P2; 1 P3 (J-OBS). Found 5 P2 this round (Home dup card, wheel back-stack, duplicate app bar, dark paywall contrast, recovery-phrase wrong store) — ALL fixed + verified live + regression-clean (0 FATAL, content still `enc:v1:`). E-GAME-002 confirmed live + pruned. Security cornerstone clean (D1–D7). Fixes in working tree — user commits.**
|
||||
> **Verdict (2026-06-27): R11 confirmation round COMPLETE — FLAWLESS (0 open P0–P2). Fixed the last open P2 (C-DARKART-001 — dark art now follows the in-app theme) + the open P3 (C-ART-EDGE-001 — art feathers into the surface), both in the shared `BrandIllustration`/`EmptyState` helpers, verified live on both decoupled theme directions (system-light+app-Dark → dark aubergine art; system-dark+app-Light → light pastel art), 0 FATAL. Re-confirmed all 5 R10 P2 fixes hold (C-HOME-001 single card · C-NAV-002 wheel-back popUpTo present · C-NAV-003 single app bar live · C-PW-001 dark paywall pills legible live · C-SEC-001 recovery row active for accepter live) → pruned. Entrypoint launch-integrity smoke green (splash-crash class clean on the fresh APK). Only remaining: 2 freshly-fixed art items pending 1 confirm + J-OBS (P3 touch targets). Art fixes in working tree — user commits.**
|
||||
|
||||
> **📖 Architecture reference:** see [`docs/Engineering_Reference_Manual.md`](docs/Engineering_Reference_Manual.md). Most fixed-and-pruned IDs above are documented in its [Known landmines and recent fixes](docs/Engineering_Reference_Manual.md#known-landmines-and-recent-fixes) section — read before re-touching the affected area.
|
||||
>
|
||||
> **Verdict (2026-06-26): R10 FULL ClaudeQAPlan run COMPLETE (A–J + fix phase). 0 open P0–P2; 1 P3 (J-OBS). Found 5 P2 (Home dup card, wheel back-stack, duplicate app bar, dark paywall contrast, recovery-phrase wrong store) — ALL fixed + verified live + regression-clean. E-GAME-002 confirmed live + pruned. Security cornerstone clean (D1–D7). [Pruned in R11.]**
|
||||
>
|
||||
> This report shows **current state only**. Fixed issues live here for **one** confirmation round, then they're pruned
|
||||
> to the archived-ID line below (full detail stays in git history). See **Report hygiene** in `ClaudeQAPlan.md`.
|
||||
|
||||
## Run-state (current)
|
||||
`R10 (2026-06-26) full ClaudeQAPlan run COMPLETE | A ✅ B ✅ C ✅ D ✅ E ✅ F ✅ G ✅ H ✅ I ✅ J ✅ | Fix phase ✅ — 5×P2 fixed+verified live (C-HOME-001 · C-NAV-002 · C-NAV-003 · C-PW-001 · C-SEC-001) | E-GAME-002 confirmed+pruned | 0 open P0–P2; 1 P3 (J-OBS) | Baseline: both FREE, 0 active sessions; build installed both emulators | NEXT (R11 = next session): brief confirmation round → re-verify the 5 P2 fixes hold + regression sweep → prune the 5 Fixed rows → flawless. Optional: J-OBS (P3) touch targets. App fixes in working tree (user commits).`
|
||||
- **Uncommitted (user commits):** `functions/src/games/onGameSessionUpdate.ts` (DEPLOYED live), `app/.../MainActivity.kt` + `app/.../notifications/PartnerNotificationManager.kt` (E-GAME-002). **+ Foreground game-alert feature (this session, app rebuilt+installed both):** NEW `notifications/GamePromptController.kt`, `ui/components/GamePromptBanner.kt`; edited `core/navigation/AppNavigation.kt`, `core/notifications/AppMessagingService.kt`, `ui/home/HomeScreen.kt`, `ui/home/HomeViewModel.kt`, `ui/wheel/WheelSessionViewModel.kt`. Note: reinstalling the debug APK can leave a stale FCM token until re-register on next launch.
|
||||
`R12 (2026-06-27) FRESH FULL ClaudeQAPlan run STARTED (user: "start from the start") | Baseline verified clean: QA free, Sam free (premium revoked), 0 active sessions; build HEAD 2cd0af6 + 3 uncommitted art files installed both emulators (5554=Dark, 5556=Light) | A ✅ (A-201 P1 Date-Match premium bypass) | B ✅ (4 async games full 2-device end-to-end + first-finisher nudge + C-NAV-002 + Ready=Start re-verified live; CC/MemoryLane/DateMatch render-checked; MemoryLane title/preview run-on→Future) | C ✅ (regression-clean vs R10 sweep; Messages/Today/Subscription + organic A/B + R11 decoupled art; NEW C-ART-EDGE-002 P3 direct-call hero hard edges on dark) | D ✅ (LIVE: D1 game answers enc:v1: · D3 non-member 403×4 + member-scoped · D5 self-grant→403; D2/D4/D6/D7 carried R7/R10, rules unchanged) — cornerstone clean | E ▶ in progress (Pass B already verified start/first-finisher/finish triggers→correct partners+copy; cold-start tap smoke running bg bjffibz4v) | F–J todo | Admin: scratchpad/qadmin.js + qa/* + scratchpad/d3neg.js (raw-API). Baseline restored (both free, 0 active). | NEXT: confirm smoke 6/6, then Pass F resilience. Carryover from R11 (still valid): C-DARKART-001 (P2) + C-ART-EDGE-001 (P3) fixed pending 1 confirm; J-OBS (P3) open touch targets.`
|
||||
- **(prior) R11 (2026-06-27) confirmation round COMPLETE — FLAWLESS | Fixed last open P2 C-DARKART-001 (in-app-theme art) + P3 C-ART-EDGE-001 (feathered edges) in shared BrandIllustration/EmptyState; verified live both decoupled theme directions, 0 FATAL | 5 R10 P2 fixes re-confirmed + PRUNED (C-HOME-001/C-NAV-002/C-NAV-003/C-PW-001/C-SEC-001) | entrypoint smoke green on fresh APK | 0 open P0–P2 | Baseline: both FREE, 0 active sessions; build (HEAD 2cd0af6 + 3 uncommitted art files) installed both emulators | NEXT (R12 = next session): confirm C-DARKART-001 + C-ART-EDGE-001 hold → prune; optional J-OBS (P3) touch targets; then declare program-complete for Android. Art fixes in working tree (user commits).`
|
||||
- **Pass B progress (R12):** **1. This or That ✅** — full end-to-end 2-device, NEW style **Light×5 Quick** (R10 was Deep×10): QA started → answered 5 (alt A/B) → first-finisher state; **first-finisher nudge fired** (`partFinishNotifiedAt` set + Sam queue `partner_completed_part` "QA finished their part — your turn to play!"); Sam **joined via Play-hub active state** (at Q1/5, no dup session) → answered all-A → session→completed (0 active); **`partner_finished_game` to BOTH**; reveal **3/5 in sync** symmetric + correct Match/Differ + You/QA attribution on **both** devices (QA dark / Sam light). 0 FATAL. **2. Spin the Wheel ✅** — **Ready=Start session** (R11 change) verified; spun→Stress→10Q; **mixed answer types** (free-text + 1–5 scale) render+accept; Sam **joined active session** via Play hub (Q1, no dup/new spin); both finished→completed (0 active); results "Here's how you each answered" with You/QA free-text + scale; **C-NAV-002 RE-VERIFIED LIVE** — results → BACK → wheel hub (Spin/History), NOT the finished session (the R11-deferred confirm). 0 FATAL. **3. How Well ✅** — QA subject 5·Quick (answered 5 about self), Sam **joined as guesser** ("Predict how QA answered…", asymmetric), guessed 5 → score **5/5 "Perfect read"** + per-Q breakdown (✓ + answer, choice+scale) symmetric both devices; completed (0 active). **4. Desire Sync ✅** (premium, couple-shared via Sam-on) — free QA opened setup (no paywall); QA all-Yes, Sam joined + Y,Y,Y,N,N → reveal **"3 shared desires · 2 kept private"** (only mutual-Yes shown, 2 mismatches "Private") symmetric both devices; completed (0 active); Sam premium restored OFF. **All 4 async session games verified end-to-end.**
|
||||
- **Uncommitted (user commits):** R11 art fixes only — `app/.../ui/theme/Theme.kt` (LocalAppInDarkTheme CompositionLocal), `app/.../ui/components/BrandIllustration.kt` (theme-correct `-night` variant via config-overridden context + edge feathering), `app/.../ui/components/EmptyState.kt` (routes its illustration through BrandIllustration). Everything else (splash fix, E-GAME-003, foreground banner, qa/ tooling) committed by user in `2cd0af6`.
|
||||
- **Foreground "partner started a game" alert + bold Game Waiting card (R10, user-requested) — DONE+VERIFIED.** When the app is OPEN and a partner starts a game, a prominent **in-app top banner** ("<partner> started <Game>" + Join) slides in (mirrors chat's in-app surface) instead of the easy-to-miss system notification; **Join → joins the game**. Verified live for all 4 session games: banner name correct (Spin the Wheel / This or That / How Well Do You Know Me / Desire Sync); Join → joins wheel (ToT shows graceful "QA is playing a Wheel game" when types mismatch); **suppressed** when already on that game's screen (added `ActiveGameSessionMonitor.enter/leave` to `WheelSessionViewModel` — the others already had it). Home **"Game waiting"** card redesigned as a **bold purple-gradient hero** (glyph + game name + "Join the game"), promoted to top of "Waiting for you", verified **both themes** → tap **joins the specific game** (not the Play-hub fallback). FCM transport on the emulators is flaky (FcmRetry); the banner was exercised via a data-only high-priority send to the partner token (faithful to the deployed payload).
|
||||
- **Pass C progress (R10):** **Settings family ✅** (dark + Security on light): Settings list, Subscription, Security, Delete account, Notifications all render clean both-relevant-themes; **4 illustrations confirmed in-context** (Security padlock, Delete-account doorway, Quiet-hours moon, + Subscription); back-stack OK (Security/Delete/Notif → BACK → Settings). **Found C-SEC-001 (P2)** — accepter's Recovery phrase disabled + wrong "invite your partner" copy (see Open issues). **Wheel back-stack RE-CHECKED = not a trap:** live wheel session → BACK → spin/setup → BACK → Play hub (2 backs, no dead-end); earlier "stuck" was automation cycling. Leaving mid-wheel leaves a resumable abandoned active session (normal; cleaned). Home ✅ both themes (stale game card gone).
|
||||
- **6. Spin the Wheel ✅** — spun→Physical Intimacy→session; Sam joined at Q1; both answered 10 (A/B + 1–5 scale + free-text); per-Q You/QA breakdown renders; completed, 0 active. (Helper `wheel_drive.py` handles mixed types; free-text Qs hide "Next" behind IME.)
|
||||
|
|
@ -28,31 +34,30 @@
|
|||
| Severity | Open | Fixed (pending 1 confirm) |
|
||||
|---|---|---|
|
||||
| P0 | 0 | 0 |
|
||||
| P1 | 0 | 0 |
|
||||
| P2 | **1** | **5** |
|
||||
| P3 | **2** | 0 |
|
||||
| P1 | **1** (A-201) | 0 |
|
||||
| P2 | **0** | **1** (C-DARKART-001) |
|
||||
| P3 | **2** (J-OBS, C-ART-EDGE-002) | **1** (C-ART-EDGE-001) |
|
||||
|
||||
## Issues — R10 (1 open P2 [C-DARKART-001] · 5×P2 fixed pending 1 confirm · 2 open P3 [J-OBS, C-ART-EDGE-001])
|
||||
> Each P2 below was found in R10's report-only passes, then fixed + verified live in the R10 fix phase (build
|
||||
> succeeded, both emulators reinstalled, 0 FATAL, content still `enc:v1:` at rest). Per hygiene they survive **one**
|
||||
> confirmation round, then prune. **Fix commits are in the working tree (user commits).** Quick fix summary:
|
||||
> C-HOME-001 `buildPendingActions().filterNot{it.target==primary?.target}` · C-NAV-002 `popUpTo(WHEEL_SESSION){inclusive}` on session→complete ·
|
||||
> C-NAV-003 removed WHEEL_HISTORY/GAME_HISTORY/PARTNER_HOME from `shellBackRoutes` · C-PW-001 `BenefitPill` text→`PurpleDeep` ·
|
||||
> C-SEC-001 `SecurityViewModel` reads `encryptionManager.recoveryPhrase(coupleId)` (CoupleKeyStore) + corrected copy.
|
||||
## Issues — R12 (1 open P1 [A-201 date-match premium bypass] · 0 open P2 · 1×P2 fixed pending 1 confirm [C-DARKART-001] · 1 open P3 [J-OBS] · 1×P3 fixed pending 1 confirm [C-ART-EDGE-001])
|
||||
> R11 fixed the two open art issues in the shared `BrandIllustration`/`EmptyState` helpers and verified both live
|
||||
> on **both** decoupled theme directions, 0 FATAL. The 5 R10 P2 fixes were re-confirmed this round and **pruned** to the
|
||||
> archived-ID line below (detail in git `9c84c36`). **Fixes for the two art issues are in the working tree (user commits).**
|
||||
> Fix summary: C-DARKART-001 — `LocalAppInDarkTheme` CompositionLocal (set in `CloserTheme`) drives a config-overridden
|
||||
> context (`createConfigurationContext` with `UI_MODE_NIGHT_*` from the in-app theme) so `-night` art follows the app's
|
||||
> own theme, not the system. C-ART-EDGE-001 — tiled art feathers its 4 edges to transparent (`graphicsLayer{Offscreen}` +
|
||||
> `drawWithContent` `BlendMode.DstIn` linear gradients) instead of a hard `clip` + `border`; `EmptyState` now routes its
|
||||
> illustration through `BrandIllustration` so both fixes apply everywhere from one place.
|
||||
|
||||
| ID | Sev | Area | Description | Repro | Suggested fix | Status |
|
||||
|---|---|---|---|---|---|---|
|
||||
| C-ART-EDGE-001 | P3 | Art / edge treatment (Pass C+H, R10) | **Displayed illustrations have hard edges instead of fading into the screen.** `BrandIllustration` (`BrandIllustration.kt:35-39`) hard-`clip`s art to `RoundedCornerShape(28.dp)` + a hairline `border`, and `EmptyState` (`EmptyState.kt:43`) renders raw `painterResource` — so the art's near-white/tile background reads as a crisp rounded-rectangle card boundary on the screen (especially visible on dark theme) instead of blending in. Affects every tiled illustration app-wide, both themes. | Any art screen (e.g. Security padlock, Memory Lane, empty states): the illustration shows a hard tile edge/outline rather than feathering into the background. | Feather the edges to transparent in the shared `BrandIllustration`/`EmptyState` helpers (radial/linear fade mask via `graphicsLayer{compositingStrategy=Offscreen}` + `drawWithContent` `BlendMode.DstIn` gradient), or a vignette matching the surface; OR ship transparent/feathered-edge art. Apply once in the shared helpers for consistency. | **Open (P3)** |
|
||||
| C-DARKART-001 | P2 | Theme / dark-mode art (Pass C, R10) | **Dark-mode illustrations don't follow the IN-APP theme switch — only the system dark mode.** The in-app toggle (Settings → Appearance → Dark) swaps Compose colors via `CloserTheme(darkTheme=…)` but there's **no** `AppCompatDelegate.setDefaultNightMode`/config `uiMode` override, so `painterResource` + the `drawable-night-nodpi/` variants resolve off the **system** `uiMode`. Result: a user who switches the app to Dark while their phone is in light mode gets **dark UI + light illustrations** (bright tile clashing on the dark screen). Affects all 12 `-night` illustrations. | 5554: `cmd uimode night no` (system light) → Settings → Appearance → **Dark** → Security shows the **light** padlock tile on a dark screen. With `cmd uimode night yes` the **dark** aubergine variant correctly appears → proves the art follows system, not the app. | Drive the resource `uiMode` from the in-app theme: a themed `Resources` in the shared `BrandIllustration` helper (load the bitmap from a `createConfigurationContext` with `UI_MODE_NIGHT_*` set from the app theme), OR `AppCompatDelegate.setDefaultNightMode` / `applyOverrideConfiguration`. Verify every `-night` screen after. | **Open (P2)** |
|
||||
| C-NAV-003 | P2 | Nav / duplicate header (Pass C, R10) | **Two stacked app bars (double back arrow) on Wheel History / Past Games** — regression of the C-CC-001 class. `WHEEL_HISTORY` + `GAME_HISTORY` are in `shellBackRoutes` (AppNavigation.kt:615-616) so the shell draws a "Wheel History" back bar, but `GameHistoryScreen` (`WheelHistoryScreen.kt:69-72`) renders its **own** `Scaffold`+`TopAppBar("Past Games")` → two title bars + two back arrows stacked. A grep of every `shellBackRoutes` screen shows exactly two that own a `TopAppBar`: GameHistory (verified live) and **PartnerHome** (`PartnerHomeScreen.kt:228`, `PARTNER_HOME` in shellBackRoutes:594, reachable via Home StreakCard `onPartner`) — same defect, code-confirmed. | 5554: Play → Spin the Wheel → History → screen shows "← Wheel History" bar over "← Past Games" bar over "Past games" content. | Remove `WHEEL_HISTORY`, `GAME_HISTORY`, `PARTNER_HOME` from `shellBackRoutes` (the screens own their headers) — exactly the fix applied to CONNECTION_CHALLENGES for C-CC-001 (see comment at AppNavigation.kt:609). | **Fixed + verified live R10 (working tree; user commits)** |
|
||||
| C-PW-001 | P2 | Paywall / dark-mode contrast (Pass C, R10) | **Paywall "What's included" benefit pills are near-invisible in dark theme.** `BenefitPill` (`PaywallScreen.kt:246`) draws a hardcoded **light** background `CloserPalette.PurpleMist` but sets text `color = MaterialTheme.colorScheme.onSurface`, which is near-white on dark → light-on-light, text barely legible (the `PurpleDeep` checkmark stays visible). Light theme is fine. Same class as the fixed C-DS-001. | 5554 (dark): Play → Desire Sync (both free) → Paywall → "What's included" list rows show white pills with unreadable labels (confirmed via crop; text present in hierarchy). 5556 (light): same rows legible. | Give `BenefitPill` text a fixed dark brand color (e.g. `CloserPalette.PurpleDeep` / `0xFF56306F`, matching the checkmark) since the pill background is always light, OR make the pill background theme-adaptive. | **Fixed + verified live R10 (working tree; user commits)** |
|
||||
| C-NAV-002 | P2 | Nav / back-stack (Pass C, R10) | **Finishing Spin-the-Wheel → results → system BACK re-enters the completed Wheel Session play screen** (shows "10/10, Finish/Skip/End session"), then BACK again → Wheel hub. The session→complete nav uses plain `navigateRoute` (`else → navController.navigate`, no `popUpTo`), so the finished play screen stays on the back stack. This is the "WATCH — wheel back-stack" item flagged in B; now deliberately reproduced on 5556 (not an automation artifact). | 5556: play a wheel to completion → auto-lands on Complete/results → BACK → lands inside the finished Wheel Session screen. | When navigating WHEEL_SESSION→WHEEL_COMPLETE, `popUpTo(WHEEL_SESSION){inclusive=true}` (or pop in WheelSessionScreen on navigateTo) so BACK from results returns to the wheel hub/Play, not the finished play screen. | **Fixed + verified live R10 (working tree; user commits)** |
|
||||
| C-HOME-001 | P2 | Home / UI redundancy (Pass C, R10) | **Home shows the top pending action twice.** `HomePriorityEngine` picks a `primaryAction` (rendered as the big `PrimaryHomeActionCard` hero) while `buildPendingActions()` independently re-adds the same item to the "Waiting for you" list — no exclusion of the primary. Seen live: "Challenge waiting" appears both as a compact "Waiting for you" row AND as the prominent hero below it. Applies to every pending type (reveal/partner-answered/game/challenge/date/capsule) whenever the engine's primary overlaps the pending list. | 5554 Home (paired, challenge in progress): two "Challenge waiting" cards stacked (list row + hero). | In `buildPendingActions()` (or at the call site) drop the card whose target matches `primaryAction.target` so each waiting item surfaces once. | **Fixed + verified live R10 (working tree; user commits)** |
|
||||
| C-SEC-001 | P2 | Security / recovery — wrong store (Pass C+D4, R10) | **SecurityScreen reads the wrong recovery-phrase store, so the accepter can't view/copy their phrase there.** Two stores exist: `RecoveryPhraseStore` (global `closer_recovery/recovery_phrase`) is written **only** by the inviter's `InviteRepositoryImpl.createInvite` (line 43); the accepter's `CoupleEncryptionManager.unwrapAndStore` persists the phrase in `CoupleKeyStore` (`recovery_phrase_$coupleId`, line 71). `SecurityScreen` (`SecurityScreen.kt:82,92`) reads `recoveryPhraseStore.load()` (global) → null for the accepter → row greyed + misleading copy *"becomes available after you invite your partner"*. `EditProfileViewModel` (reads `encryptionManager.recoveryPhrase(coupleId)` → CoupleKeyStore) shows it correctly for both. **D4 verified the accepter DOES hold the phrase and CAN recover the couple key — E2EE recovery is sound (not data-loss); this is a UI wrong-source bug.** | 5554 (QA, accepter): Settings → Security → Recovery phrase greyed + that copy. 5556 (Sam, inviter): active. EditProfile shows it for QA. | Make `SecurityScreenViewModel` read the phrase via `encryptionManager.recoveryPhrase(coupleId)` (CoupleKeyStore, the same source EditProfile uses) instead of the global `RecoveryPhraseStore`; fix the unavailable-state copy. | **Fixed + verified live R10 (working tree; user commits)** |
|
||||
| A-201 | P1 | Premium / Date Match bypass (Pass A, R12) | **Premium date ideas are NOT gated — free users can view, swipe, like and match them with no paywall.** `DateIdea.isPremium` is documented as "requires an active premium entitlement," but `DateMatchRepositoryImpl.getDateIdeas()` returns `DateIdeaSeed.all` (premium ideas included, **no entitlement filter**), `DateMatchViewModel` loads them with no `CouplePremiumChecker`, and `DateMatchScreen` only renders a cosmetic `PremiumBadge()` — no lock overlay, no paywall on like/super-like. So the premium tier for Date Match is unenforced. **Escaped prior Pass A rounds** (which asserted "all gates use CouplePremiumChecker" — Date Match has NO gate). (Plan buckets "premium bypass" as P0; filed P1 as it's a content-tier subset, no security/data impact.) | 5554 (QA **free**): Play → Date Match → reject through deck → reach a **★ Premium** idea ("night camping getaway") → Like (heart) → **no paywall**, swipe accepted, deck advanced to the next premium idea ("Zipline canopy tour"); 0 FATAL, no `PERMISSION_DENIED`. | Gate premium date ideas through `CouplePremiumChecker`: either filter `isPremium` ideas out of a free couple's deck, OR intercept like/super-like on a premium idea → route to Paywall when neither partner is premium (couple-shared). Mirror the Desire Sync / Question-pack gate. | **Open (P1)** |
|
||||
| C-DARKART-001 | P2 | Theme / dark-mode art (Pass C) | **Dark-mode illustrations didn't follow the IN-APP theme switch — only the system dark mode.** The in-app toggle (Settings → Appearance → Dark) swapped Compose colors via `CloserTheme(darkTheme=…)` but had no config `uiMode` override, so `painterResource` + the `drawable-night-nodpi/` variants resolved off the **system** `uiMode` → app-Dark on a light-mode phone showed **dark UI + light illustrations**. Affected all 12 `-night` illustrations. | 5554: `cmd uimode night no` (system light) → Settings → Appearance → **Dark** → before fix Security showed the **light** padlock tile on a dark screen. | **DONE:** `BrandIllustration` loads the drawable through `context.createConfigurationContext(cfg)` with `UI_MODE_NIGHT_*` set from `LocalAppInDarkTheme` (provided in `CloserTheme`). **Verified live R11 both directions:** 5554 system-light + app-Dark → **dark aubergine** art on dark screen (Security + Art-preview gallery); 5556 system-dark + app-Light → **light pastel** art on light screen; 0 FATAL, both apps alive. | **Fixed + verified live R11 (working tree; user commits)** |
|
||||
| C-ART-EDGE-001 | P3 | Art / edge treatment (Pass C+H) | **Displayed illustrations had hard edges instead of fading into the screen** — `BrandIllustration` hard-`clip`ped art to `RoundedCornerShape` + a hairline `border`, and `EmptyState` rendered raw `painterResource`, so the near-white tile read as a crisp rounded-rectangle boundary (esp. on dark). | Any art screen: hard tile edge/outline instead of feathering. | **DONE:** tiled art now feathers its 4 edges to transparent (`graphicsLayer{compositingStrategy=Offscreen}` + `drawWithContent` `BlendMode.DstIn` linear gradients, ~14% inset); `clip`+`border` removed; `EmptyState` routes through `BrandIllustration`. **Verified live R11:** Art-preview gallery + Security padlock melt softly into the surface on both themes; transparent art (`tile=false`) unaffected. | **Fixed + verified live R11 (working tree; user commits)** |
|
||||
| C-ART-EDGE-002 | P3 | Art / hard edges on direct-call heroes (Pass C, R12) | **Hero illustrations rendered via direct `painterResource` (not the shared `BrandIllustration`) still show hard edges on dark theme** — the R11 C-ART-EDGE-001 feather fix only covered `BrandIllustration`/`EmptyState`. The Today "Weekend Side Quest" daily-question hero (light/pink art) renders as a **bright rounded-rect block with a hard bottom edge on the dark screen**. These direct-call heroes have **no `-night` variant** either. Likely same class: paywall couple art, onboarding, Home tonight-prompt/partner-activation, spin-wheel hero, pack art (all direct `painterResource(illustration_*)`). Matches the user's "all images should fade into the screen" request (only partially satisfied by C-ART-EDGE-001). | 5554 (dark): Today tab → daily question → "Weekend Side Quest" hero shows a hard bright edge against the dark card. | Route these heroes through `BrandIllustration` (gains feather + theme-variant), OR apply the same `featherEdges()` treatment at each call site; consider `tile`/`hero` variants. Verify each direct `painterResource(R.drawable.illustration_*)` site listed in the R12 grep. | **Open (P3)** |
|
||||
| J-OBS | P3 | A11y / touch targets | A few conversation icon-buttons measure **~42–45dp wide** (48dp tall) — single-axis marginal miss of the 48dp target; fully operable. Most controls are 48dp. | Pass J: uiautomator bounds on conversation → 2–3 clickables `<126px` wide. | Bump those icon-buttons to 48dp min (e.g. `Modifier.minimumInteractiveComponentSize()` / `size(48.dp)`). | **Open (P3, non-blocking)** |
|
||||
|
||||
## Resolved & confirmed (archived — full detail in git history)
|
||||
A-001 · A-003 · A-OBS · B-001 · B-002 · B-003 · B-004 · C-CC-001 · C-DS-001 · C-NAV-001 · D-001 · E-001 · E-002 · E-003 · **E-GAME-002** · E-OBS · F-OBS · F-RACE-001 · **I-001** · **I-002** — all fixed and re-verified (E-GAME-002 confirmed live R10: `startNotifiedAt` set + partner_started_game queued to right partner + foreground banner + Join→joined active ToT at same Q1; commits 6e79cd9/38fdc6d) (commits in history; F-RACE-001 re-confirmed R8; **I-001** query→`whereIn(dayKeys)` + **I-002** Long-score→`Number.toInt()`, fixed `ab29f6b`, re-confirmed live R9: 0 outcomes denials/CCE). Pruned per the one-confirmation-round rule. (C-OBS / `outcomes` list / SubscriptionScreen per-user gate = investigated, **not bugs**.)
|
||||
A-001 · A-003 · A-OBS · B-001 · B-002 · B-003 · B-004 · C-CC-001 · C-DS-001 · **C-HOME-001** · **C-NAV-001** · **C-NAV-002** · **C-NAV-003** · **C-PW-001** · **C-SEC-001** · D-001 · E-001 · E-002 · E-003 · **E-GAME-002** · **E-GAME-003** · E-OBS · F-OBS · F-RACE-001 · **I-001** · **I-002** — all fixed and re-verified (R11 pruned the 5 R10 P2 fixes — C-HOME-001 single Home card · C-NAV-002 `popUpTo(WHEEL_SESSION){inclusive}` present + R10-live · C-NAV-003 single app bar re-confirmed live · C-PW-001 dark paywall pills legible re-confirmed live · C-SEC-001 recovery row active for accepter re-confirmed live — all committed in `9c84c36`; E-GAME-003 `onGamePartFinished` deployed + committed `2cd0af6`) (E-GAME-002 confirmed live R10: `startNotifiedAt` set + partner_started_game queued to right partner + foreground banner + Join→joined active ToT at same Q1; commits 6e79cd9/38fdc6d) (commits in history; F-RACE-001 re-confirmed R8; **I-001** query→`whereIn(dayKeys)` + **I-002** Long-score→`Number.toInt()`, fixed `ab29f6b`, re-confirmed live R9: 0 outcomes denials/CCE). Pruned per the one-confirmation-round rule. (C-OBS / `outcomes` list / SubscriptionScreen per-user gate = investigated, **not bugs**.)
|
||||
|
||||
## Security cornerstone — clean (Pass D, deep dive, Round 7)
|
||||
- **D1 at-rest:** chat text + `lastMessagePreview` + all 4 game-answer collections (ToT / How Well / Desire Sync / Wheel, both users) + Memory Lane capsules + date-swipe actions = `enc:v1:`. No plaintext content; only metadata in clear.
|
||||
|
|
@ -95,6 +100,17 @@ also set an `ACTION_VIEW` + `closer://` **data Uri** on the notification intent:
|
|||
path (no Uri) loads results; **warm tap from Settings now routes** (was the stuck case).
|
||||
|
||||
## Round history (one line each)
|
||||
- **R11 (2026-06-27) — confirmation round, FLAWLESS (0 open P0–P2).** Fixed the last open P2 **C-DARKART-001** (dark-mode
|
||||
art now follows the in-app theme: `LocalAppInDarkTheme` CompositionLocal in `CloserTheme` → `BrandIllustration` loads the
|
||||
`-night` drawable via a `createConfigurationContext` whose `UI_MODE_NIGHT_*` comes from the app theme, not the system) and
|
||||
the open P3 **C-ART-EDGE-001** (tiled art feathers its 4 edges to transparent via `graphicsLayer{Offscreen}` +
|
||||
`BlendMode.DstIn` gradients instead of hard `clip`+`border`; `EmptyState` now routes through `BrandIllustration`). Verified
|
||||
**live both decoupled theme directions** (5554 system-light+app-Dark → dark aubergine art; 5556 system-dark+app-Light →
|
||||
light pastel art; both feathered), 0 FATAL, both apps alive. Re-confirmed + pruned the 5 R10 P2 fixes (C-HOME-001 single
|
||||
Home card · C-NAV-002 wheel-back `popUpTo` present · C-NAV-003 single app bar live · C-PW-001 dark paywall pills legible
|
||||
live · C-SEC-001 recovery row active for accepter live). Entrypoint launch-integrity smoke green on the fresh APK (launcher
|
||||
+ notification cold-starts open & stay — splash-crash class clean). Art fixes in working tree; everything else committed
|
||||
(`2cd0af6`).
|
||||
- **E-GAME-003 (2026-06-27) — FIXED+VERIFIED+DEPLOYED: async-game first-finisher left the waiting partner un-notified.**
|
||||
Async games (this_or_that/wheel/how_well/desire_sync) write answers to `couples/{c}/{gameType}/{sessionId}` and the
|
||||
session only flips to `completed` when BOTH answer — so `onGameSessionUpdate` (watches the session doc) never fired on
|
||||
|
|
|
|||
Loading…
Reference in New Issue