diff --git a/ClaudeBrandingReview.md b/ClaudeBrandingReview.md index 58d9de86..87283a8b 100644 --- a/ClaudeBrandingReview.md +++ b/ClaudeBrandingReview.md @@ -1,13 +1,14 @@ # Closer — Branding & Artwork Review (Pass H) -Living deliverable for the **Branding pass**. It captures, screen by screen, where Closer could carry more of its -brand, and gives **ready-to-paste ChatGPT image-generation prompts** for the artwork worth adding. The user generates -the images; this file only describes them. Every prompt reuses the **House Style** block below so all new art matches -the existing artwork (`docs/brand/visual-identity.md` + `docs/brand/asset-system.md` + the shipped `illustration_*` / -`pack_art_*` / `particle_*` assets). +Living status document for Closer's brand artwork pass. It records which illustrations/glyphs are live, which surfaces +should reuse existing assets, and which brand issues belong in implementation or QA rather than image generation. + +**Current state:** no active image-generation prompts remain. A1-A12 illustrations and the G/G2 glyph sets exist; the +remaining brand work is theme polish, reuse of existing assets, or QA verification. > Branding **defects** (off-brand color, clipped/low-contrast art) → `ClaudeReport.md`. Pure "could be warmer / feature" -> ideas → `Future.md` `## QA`. New art to create → here. +> ideas → `Future.md` `## QA`. Only add new prompts here when a future QA pass proves an existing/code-native treatment +> cannot carry the brand. --- @@ -16,7 +17,7 @@ R10 visual sweep doubled as the Pass-H existing-art integration check: Today (pa Paywall (couple illustration), Security (padlock), Memory Lane / Date / Bucket-List empties, Home cards — **all render on-brand, in-context, both themes, no clipping/placeholder/off-brand issues** (any defect would be a `ClaudeReport.md` bug; none found). The new game-alert surfaces (`GamePromptBanner`, `GameWaitingHeroCard`) use the brand purple gradient -+ PlayArrow glyph and read as intentional action banners — no illustration warranted. No new art to add this round. ++ PlayArrow glyph and read as intentional action banners, so no illustration is warranted there. ## This or That gameplay brand plan (Codex QA, 2026-06-27) Live review used a dedicated QA launcher/device (`CloserCodexQA`) with a fresh admin-created test couple @@ -60,7 +61,7 @@ motif reads like a technical diagram instead of a warm private ritual for two. - Dark mode feels intentionally Closer-branded: aubergine/lavender/pink, soft and private, not a placeholder diagram. - Logs are checked after opening a game from notification/deep link before assuming the route worked. -## ✅ WIRED INTO ANDROID (2026-06-26 art drop) — generated illustrations live +## Generated Art Live The generated art (source in gitignored `docs/brand/generated-art/`, copied full-res to `app/src/main/res/drawable-nodpi/`) is now wired into the app via the shared `EmptyState` (rounded-tile, theme-safe) and a new `ui/components/BrandIllustration.kt` helper: @@ -79,15 +80,38 @@ The generated art (source in gitignored `docs/brand/generated-art/`, copied full | A11 `privacy_recovery` | SecurityScreen header | **live dark** | | A12 `account_deletion_goodbye` | DeleteAccountScreen header | **live dark** | -All 12 also live in the debug **Art preview** gallery (Settings → Art preview) for both-theme verification. -**Not done:** A7 pack art = **N/A** (all 10 packs already have `pack_art_*`). **G-set glyph art generated -2026-06-27 and ready to add** from `docs/brand/generated-art/glyphs/`; app wiring is still pending. -A1-A12 prompts are complete and should not be regenerated. Empty/match/pairing states that need empty-or-new data weren't -reachable on the baseline couple — render path proven via the shared tile + gallery. Commits `077a408`→`5868d06` on `dev`. +All 12 also live in the debug **Art preview** gallery (Settings → Art preview) for both-theme verification. A7 pack art is +**N/A** because all 10 question packs already have `pack_art_*`. + +A1-A12 prompts are complete and should not be regenerated. Empty/match/pairing states that need empty-or-new data were +not all reachable on the baseline couple, but their render path is proven through the shared tile + gallery. + +## Glyph Status + +The original G-set plus G2 set are copied into `app/src/main/res/drawable-nodpi/glyph_*.xml`. Source SVGs live in +`docs/brand/generated-art/glyphs/source-svg/`; Android handoff vectors live in +`docs/brand/generated-art/glyphs/android-vector/`. + +**Wired + verified live (13 of 17):** +- Play hub cards: `paired_cards`, `how_well`, `sealed_answer`, `connection_challenge`, `memory_capsule`, + `date_card_heart`, `question_packs`, `bucket_list`, `past_games`. +- WaitingForPartner per-game glyphs: `spin_wheel`, `paired_cards`, `how_well`, `sealed_answer`. +- Settings rows: `couple_premium`, `privacy_lock`, `delete_account`. + +**Generated but intentionally unused for now (4 of 17):** +- `closer_mark` — notifications already use `ic_notification_closer`. +- `daily_card` — Today uses its hero illustration. +- `quiet_hours_moon` — Quiet hours uses `illustration_quiet_hours`. +- `export_data` — no export-data row exists yet. + +White monochrome vectors are re-tinted by `Icon(tint = ...)` and loaded via `ImageVector.vectorResource(...)`. +`glyph_paired_cards` is also the preferred motif for the This-or-That backdrop redesign tracked as C-DARK-UI-001. --- -## House Style (paste this at the top of EVERY image prompt) +## Prompt Style Reference + +Use this only when a future pass creates a new prompt. Existing completed art should not be regenerated. > Flat 2D pastel vector **illustration** in the "Closer" couples-app style: soft rounded shapes, **no harsh outlines**, > gentle smooth gradients, calm and intimate. **Palette only:** aubergine `#24122F`, deep purple `#56306F`, lavender @@ -123,9 +147,9 @@ future QA pass finds a specific missing surface or replacement-worthy defect. --- -## Screen-by-screen audit +## Screen-By-Screen Audit -Legend: ✅ on-brand / no art needed · ➕ add/wire art · 🎨 new art to generate · 🔤 brand-copy/color touch +Legend: ✅ on-brand / no art needed · ➕ reuse/wire existing art · 🔤 brand-copy/color/code touch | Screen / surface | Current brand state | Opportunity | |---|---|---| @@ -135,18 +159,18 @@ Legend: ✅ on-brand / no art needed · ➕ add/wire art · 🎨 new art to gene | Create profile — name / sex / photo | plain steps | 🔤 light: small step glyphs; ✅ otherwise (forms stay clean) | | Pair: invite (create code) | `illustration_couple_invite` wired | ✅ | | Pair: accept code / pairing success | `illustration_pairing_success` wired | ✅ | -| Home (paired) | cards, warm copy | ✅ good; ensure card icons use brand glyphs 🔤 | +| Home (paired) | cards, warm copy | ✅ good | | Home (unpaired "bring your person in") | couple art present | ✅ on-brand | | Today / daily question | clean card | ✅; reveal moment is the place for art (below) | | Answer reveal (mutual) | `illustration_reveal_celebration` wired | ✅ | | Answer history | `illustration_answer_history_empty` wired | ✅ | -| Play hub | card list, game glyphs | ✅; verify each game card has a consistent brand glyph 🔤 | +| Play hub | game glyphs wired | ✅ | | This or That (setup/play) | light buttons good; dark prompt backdrop off-brand | 🔤 replace two-circle/line motif + theme option colors | -| This or That / How Well / Desire Sync **results** | score + rows | ➕ small celebration header art (reuse `reveal_celebration`); particles on high match | +| This or That / How Well / Desire Sync **results** | score + rows | ➕ reuse `reveal_celebration`; particles on high match | | How Well / Desire Sync intro | icon + copy | ✅ | | Spin the Wheel | nice wheel art | ✅ wheel is on-brand | | Wheel complete / results | text reveal | ➕ celebration header (reuse particles) | -| Connection Challenges (series list) | `illustration_connection_challenges_header` wired | ✅; verify per-series glyph consistency 🔤 | +| Connection Challenges (series list) | `illustration_connection_challenges_header` wired | ✅ | | Connection Challenges (active day) | clean | 🔤 small streak/heart glyph; ✅ otherwise | | Memory Lane (list) | `illustration_memory_lane_capsule` empty state wired | ✅ | | Memory Lane (sealed capsule) | lock + date | ➕ optional: reuse capsule art on sealed-card detail, no new art | @@ -160,29 +184,25 @@ Legend: ✅ on-brand / no art needed · ➕ add/wire art · 🎨 new art to gene | Past Games (empty/list) | `illustration_past_games_empty` wired | ✅ | | Your Progress / Activity | stats | 🔤 brand-colored charts; reuse `streak_milestone` for milestones | | Paywall / Subscription | couple art present | ✅ strong (couple illustration + “one subscription for both”) | -| WaitingForPartner | category glyph + copy | ✅ on-brand; ensure glyph per game type | +| WaitingForPartner | per-game glyphs + copy | ✅ | | Settings + sub-pages | dense lists | ✅ keep clean — **no illustrations**; brand via section headers/color only 🔤 | | Security / Recovery phrase | `illustration_privacy_recovery` wired | ✅ | -| Privacy & Terms | text | 🔤 small lock glyph header | +| Privacy & Terms | settings row uses `glyph_privacy_lock` | ✅; page can stay text-first | | Delete account | `illustration_account_deletion_goodbye` wired | ✅ | | Quiet hours (settings) | `illustration_quiet_hours` wired | ✅ | -| Notifications (system) | G-set glyph art generated, not wired | ➕ wire `docs/brand/generated-art/glyphs/android-vector/glyph_*.xml` | +| Notifications (system) | `ic_notification_closer` used | ✅ no glyph swap needed | --- -## Art to generate — status +## Generation Backlog -A1-A12 were generated and wired into Android. A7 is not needed because all 10 question packs already have `pack_art_*`. -G-set glyphs were generated 2026-06-27 and are ready to add from `docs/brand/generated-art/glyphs/`. There are no active -art-generation prompts right now. +**None.** Do not regenerate completed illustration or glyph art unless a future QA pass logs a specific defect that +requires replacement. -Do not regenerate completed illustration art unless a future QA pass logs a specific defect that requires replacement. -Always clean up completed art items: once an asset is generated, wired, and verified, remove its prompt from this active -backlog and update the audit table/status notes so only unfinished work remains. - -**Generated G-set files:** `glyph_closer_mark`, `glyph_paired_cards`, `glyph_daily_card`, `glyph_sealed_answer`, +**Generated glyph files:** `glyph_closer_mark`, `glyph_paired_cards`, `glyph_daily_card`, `glyph_sealed_answer`, `glyph_memory_capsule`, `glyph_date_card_heart`, `glyph_quiet_hours_moon`, `glyph_couple_premium`, -`glyph_export_data`, `glyph_delete_account`. +`glyph_export_data`, `glyph_delete_account`, `glyph_how_well`, `glyph_connection_challenge`, `glyph_question_packs`, +`glyph_bucket_list`, `glyph_past_games`, `glyph_spin_wheel`, `glyph_privacy_lock`. --- @@ -193,4 +213,3 @@ backlog and update the audit table/status notes so only unfinished work remains. Android-ready vectors in `docs/brand/generated-art/glyphs/android-vector/` for app wiring. - After adding art, re-run Pass C (visual, light + dark) on those screens to confirm contrast + no clipping, and re-export store graphics per `docs/brand/visual-identity.md` if the palette/mark changed. - diff --git a/ClaudeReport.md b/ClaudeReport.md index e90f7080..c97694bd 100644 --- a/ClaudeReport.md +++ b/ClaudeReport.md @@ -1,5 +1,7 @@ # Claude QA Report — Full-App QA (living report) +> **Verdict addendum (2026-06-27): ad hoc DARK-MODE UI/brand review on dedicated Codex emulator COMPLETE.** Built + installed the current debug APK on my own `CloserCodexQA` emulator (`emulator-5558`), forced system dark mode, created a fresh real paired couple through the app invite flow, and swept profile/onboarding, unpaired invite, paired Home, Play, This-or-That, Settings, Notifications, Paywall, Messages, and Today. **Button text is generally readable** across profile/Home/Settings/Notifications/Messages/Paywall, but the sweep found **1 open P2**: This-or-That active gameplay has low-contrast dark option text and an off-brand diagonal/circle backdrop crossing the prompt. Also found **2 open P3s**: first-launch check-in modal label/value collision and recurring bottom-inset clipping on scroll content near nav/gesture areas. Logs checked after navigation/game entry: **0 app FATAL/ANR/force-finish**; only uiautomator/system noise plus a non-crashing BillingClient unbind warning. + > **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. @@ -10,6 +12,7 @@ > to the archived-ID line below (full detail stays in git history). See **Report hygiene** in `ClaudeQAPlan.md`. ## Run-state (current) +- **Ad hoc dark-mode UI/brand sweep (2026-06-27, Codex-owned emulator `emulator-5558`):** current debug APK installed, dark mode forced, fresh real paired users created through invite flow (`Codex Dark` + `River Dark`). Swept profile, invite, paired Home, Play, This-or-That, Settings, Notifications, Paywall, Messages, Today. **0 app FATAL/ANR/force-finish in logcat.** Findings added below: C-DARK-UI-001 (P2), C-DARK-UI-002 (P3), C-DARK-UI-003 (P3). Screenshots captured at `/tmp/closer-dark-04-after-permission.png` through `/tmp/closer-dark-25-today.png`. `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 ✅ (smoke 6/6 + Pass B triggers) | F ✅ (concurrency+process-death+offline) | G ✅ (security half live) | H (finding C-ART-EDGE-002) | I ✅ (jank 4.10%) | J (J-OBS P3) | **FIX PHASE ✅ — A-201 (P1) FIXED+VERIFIED LIVE** (Date Match LOVE/MAYBE on premium idea → Paywall via CouplePremiumChecker; SKIP passes; 0 FATAL). C-DARKART-001+C-ART-EDGE-001 held → PRUNED. | **R12 COMPLETE — FLAWLESS: 0 open P0–P2.** Remaining: 2 non-blocking P3s (C-ART-EDGE-002 hero edges, J-OBS touch targets). | NEXT (R13): confirm A-201 holds → prune; optional P3 polish. Uncommitted (user commits): R11 art files + `ui/dates/DateMatchViewModel.kt` + `ui/dates/DateMatchScreen.kt` (A-201). 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.** @@ -35,8 +38,17 @@ |---|---|---| | P0 | 0 | 0 | | P1 | 0 | **1** (A-201) | -| P2 | 0 | 0 | -| P3 | **2** (J-OBS, C-ART-EDGE-002) | 0 | +| P2 | **1** (C-DARK-UI-001) | 0 | +| P3 | **4** (J-OBS, C-ART-EDGE-002, C-DARK-UI-002, C-DARK-UI-003) | 0 | + +## Issues — ad hoc dark-mode UI/brand review (2026-06-27) +> Dedicated emulator: `CloserCodexQA` / `emulator-5558`; fresh paired users created through the real invite flow; system dark mode forced. This pass focused on brand fit, image integration, dark-mode button/text visibility, route integrity, and logs after navigation/game launch. **Clean surfaces:** profile creation, invite, paired Home, Settings ("Connected with Codex Dark"), Notifications, Messages, and Paywall primary content/buttons are readable and on-brand in dark mode. **Known C-ART-EDGE-002 reproduced:** Today's direct-call hero art still appears as a bright pasted light tile on dark, already tracked below. + +| ID | Sev | Area | Description | Evidence / repro | Suggested fix | Status | +|---|---|---|---|---|---|---| +| C-DARK-UI-001 | P2 | This or That / dark active gameplay | **Dark-mode gameplay still looks off-brand and weakly legible.** The diagonal line + two-circle backdrop cuts through the question and reads like a forgotten placeholder, especially in dark mode. A/B option labels and option text are too dim on the dark cards; mood-picker duration chips are also low-contrast. This is the one screen where dark button/choice text does not meet the rest of the app's standard. | `emulator-5558`: Play → This or That → choose mood/count → active question. Screenshot: `/tmp/closer-dark-20-this-or-that-game.png`; setup chip contrast: `/tmp/closer-dark-19-this-or-that-mood.png`. Logcat after launch: 0 app FATAL/ANR/force-finish. | Replace the placeholder-like line/circle motif with branded game art or a subtle surface treatment; use theme tokens with high-contrast option text for dark; verify A/B cards, selected/pressed/disabled states, and all mood/count chips in both themes. | **Open** | +| C-DARK-UI-002 | P3 | Paired Home / first-launch check-in modal | **Slider label and value collide in dark mode.** The second check-in row reads visually like `communicate?5` because the label runs into the numeric value. Button text ("Submit", "Skip for now") is readable, but the modal needs spacing/layout polish. | `emulator-5558`: first paired Home launch opened the quick check-in modal. Screenshot: `/tmp/closer-dark-16-paired-home.png`. | Give slider rows a stable two-column layout or wrap/value-align the score independently; verify at default and larger font scales. | **Open** | +| C-DARK-UI-003 | P3 | Insets / bottom navigation and gesture area | **Several dark-mode scroll surfaces render useful content too close to or under bottom nav/gesture areas.** Play clips the lower "Desire Sync" card behind bottom nav; unpaired Home's bottom CTA is too tight to the nav area; Paywall's "Already subscribed? / Restore" card starts under the gesture area. Text is mostly readable, but it looks unfinished and can hide tap targets. | Screenshots: `/tmp/closer-dark-18-play.png`, `/tmp/closer-dark-07-post-profile.png`, `/tmp/closer-dark-23-paywall.png`. | Audit scaffold/content padding for bottom nav + system gesture insets; add consistent `navigationBarsPadding`/bottom spacer to scrollable content and modal/fullscreen paywall surfaces. | **Open** | ## Issues — R12 (0 open P0–P2 = FLAWLESS · A-201 P1 fixed+verified-live pending 1 confirm · 2 open P3 [J-OBS, C-ART-EDGE-002]) > R12 was a FRESH FULL A–J run. Found A-201 (P1, Date Match premium bypass) — **fixed + verified live this round** (gated diff --git a/Future.md b/Future.md index 9827edb5..f4893c5c 100644 --- a/Future.md +++ b/Future.md @@ -7,35 +7,18 @@ Non-blocking ideas: things that work today but could be better, plus feature ide Improvement & feature ideas surfaced while QA-testing as a consumer (each works today — none are defects). -- **Memory Lane capsule list: separate title from body preview.** (R12 Pass B) In the capsule list each row runs - the title straight into the body preview with no separator/space/style break (e.g. "QA Memory Test" + "Remember this - QA round…" renders as one run-on string). Give the preview its own line / muted style, or a separator, so title and - body read distinctly. (Partly confounded by R12 adb-typed test titles — re-check with clean data; cosmetic only.) +- **✅ DONE — Consistent brand glyphs across game cards + waiting surfaces.** G-set + G2 (17 glyphs) in + `res/drawable-nodpi/glyph_*.xml`; **13 wired + verified live:** every Play-hub card (This or That, How Well, Desire + Sync, Connection Challenges, Memory Lane, Date Match, Plan Date, Question Packs, Bucket List, Past Games — Spin the + Wheel keeps its full illustration), WaitingForPartner per-game glyph, and Settings (Subscription/Security/Privacy/ + Delete). 4 unused have no clean slot (notif uses `ic_notification_closer`; Today uses hero art; quiet-hours uses its + illustration; no export-data row exists). Full map in `ClaudeBrandingReview.md`. _(This-or-That backdrop redesign is + Codex C-DARK-UI-001.)_ -- **Consistent brand glyphs across game cards + waiting/notification surfaces.** _(Blocked: needs the - generated G-set art — image generation is the user's step per `ClaudeBrandingReview.md`.)_ Game cards - (Play hub), the WaitingForPartner screen, and notifications mix Material icons with brand art. A small - custom glyph set (the C-heart-keyhole mark, paired/sealed card, daily card, capsule, date-card, - quiet-hours moon) used consistently would strengthen identity. Generate the G-set, drop the assets in, - then wire them in. *Prompted by:* Pass H branding review. - -- **Notify the free partner when the couple gains premium.** When one partner subscribes, the other's app unlocks - (couple-shared premium) but they get **no notification** — they only find out next time they open a gated feature. A - `subscription_entitlement_changed` push ("You both have Premium now ✨") would close the loop. *Prompted by:* Pass E - (R8): the type isn't implemented; couple-shared unlock is silent for the non-subscriber. - **Minor proactive-notification gaps (low priority).** No push when a partner *joins* your active game (`partner_joined_game`) or *ends/abandons* one (`game_ended`/`game_abandoned`) — the other partner sees it in-session / on WaitingForPartner, so nothing's broken, just less proactive. *Prompted by:* Pass E (R8) inventory — these speculative types aren't implemented. -- **Retry the daily-reveal `isRevealed` write so the "partner opened" push is never silently lost.** - `performCoupleKeyReveal` sets local Room `markRevealed` *then* the Firestore `markRevealed` (best-effort, - `runCatching`). If that Firestore write fails (offline/transient), Room is already revealed → re-opening the reveal - takes `load()`'s auto-decrypt branch (which only runs when local `isRevealed==true`) and **never retries** the - Firestore write, so `onAnswerRevealed` never fires and the partner never gets the "opened your answers" push. Normal - online flow is fine (verified live). Fix: on reveal-screen load, if local says revealed but the server doc's - `isRevealed` is still false, re-issue `markRevealed`. *Prompted by:* daily-reveal QA (2026-06-26) — low severity - (content reveal unaffected; only the courtesy push on a write-failure edge). - - **Clarify Connection Challenges day-progress when partners are out of step.** If one partner catches up a *missed* day ("Pick it back up") while the other doesn't, the two devices show different **"Day N of 7"** (seen R10: QA Day 4 vs Sam Day 3) even though the 🔥 streak stays in sync on both. Not broken (plausibly individual-pace-through-the-series by design), but two people in the same shared challenge seeing different day numbers is confusing — consider a shared "you're on Day N together" framing or a clearer caught-up/ahead indicator. *Prompted by:* Pass B (R10) Connection Challenges playthrough. ### Security hardening (defense-in-depth — not vulnerabilities; rules already hold) @@ -44,14 +27,28 @@ Improvement & feature ideas surfaced while QA-testing as a consumer (each works Check token** (raw Firestore REST) returned `200` for a member — so rules are the *sole* gate. Rules correctly deny non-members/cross-couple (all `403`), so this is not a live hole, but enabling App Check enforcement on Firestore would block non-app clients entirely (defense-in-depth). *Prompted by:* R7 D3 raw-API angle. -- **Tighten the `users/{uid}` update rule to a field allowlist.** The rule only blocks changing `hasPremium`; a user - can write arbitrary *other* fields to their own doc (e.g. a cosmetic `plan`/junk). No gate reads those (premium gates - on the server-only `users/{uid}/entitlements/premium` subcollection + `category.access`), so it grants nothing — but - restricting updates to a known field set is cleaner. *Prompted by:* R7 D3 (`plan` field writable, unused by gating). > Artwork to generate (ChatGPT prompts, house-style-matched) lives in `ClaudeBrandingReview.md`, not here.