From 13ed5b362ff21e99101c60dc17fa8a62d1393bde Mon Sep 17 00:00:00 2001 From: null Date: Sun, 28 Jun 2026 11:02:18 -0500 Subject: [PATCH] =?UTF-8?q?docs(manual):=20Batch=201=20=E2=80=94=20correct?= =?UTF-8?q?=20repository=20layout=20paths=20(core/feature,=20QuestionDao,?= =?UTF-8?q?=20QuestionJsonParser)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClaudeQAPlan.md | 18 ++- Engineering_Reference_Manual_Plan.md | 92 +++++++++++++++ .../closer/ui/dates/DateBuilderViewModel.kt | 4 - app/src/main/res/drawable-nodpi/glyph_add.xml | 3 + .../res/drawable-nodpi/glyph_attach_money.xml | 3 + .../main/res/drawable-nodpi/glyph_back.xml | 3 + .../main/res/drawable-nodpi/glyph_bell.xml | 3 + .../main/res/drawable-nodpi/glyph_cake.xml | 3 + .../res/drawable-nodpi/glyph_calendar.xml | 3 + .../main/res/drawable-nodpi/glyph_camera.xml | 3 + .../drawable-nodpi/glyph_card_giftcard.xml | 3 + .../main/res/drawable-nodpi/glyph_chat.xml | 3 + .../main/res/drawable-nodpi/glyph_check.xml | 3 + .../main/res/drawable-nodpi/glyph_close.xml | 3 + .../main/res/drawable-nodpi/glyph_copy.xml | 3 + .../main/res/drawable-nodpi/glyph_couple.xml | 3 + .../main/res/drawable-nodpi/glyph_edit.xml | 3 + app/src/main/res/drawable-nodpi/glyph_eye.xml | 3 + .../main/res/drawable-nodpi/glyph_eye_off.xml | 3 + .../res/drawable-nodpi/glyph_fingerprint.xml | 3 + .../main/res/drawable-nodpi/glyph_forward.xml | 3 + .../main/res/drawable-nodpi/glyph_heart.xml | 3 + .../drawable-nodpi/glyph_heart_outline.xml | 3 + .../main/res/drawable-nodpi/glyph_home.xml | 3 + .../res/drawable-nodpi/glyph_hourglass.xml | 3 + app/src/main/res/drawable-nodpi/glyph_key.xml | 3 + .../main/res/drawable-nodpi/glyph_lock.xml | 3 + .../res/drawable-nodpi/glyph_lock_open.xml | 3 + app/src/main/res/drawable-nodpi/glyph_mic.xml | 3 + .../res/drawable-nodpi/glyph_open_in_new.xml | 3 + .../main/res/drawable-nodpi/glyph_palette.xml | 3 + .../main/res/drawable-nodpi/glyph_pause.xml | 3 + .../main/res/drawable-nodpi/glyph_person.xml | 3 + .../main/res/drawable-nodpi/glyph_photo.xml | 3 + .../main/res/drawable-nodpi/glyph_play.xml | 3 + .../res/drawable-nodpi/glyph_psychology.xml | 3 + .../drawable-nodpi/glyph_question_answer.xml | 3 + .../main/res/drawable-nodpi/glyph_refresh.xml | 3 + .../main/res/drawable-nodpi/glyph_send.xml | 3 + .../res/drawable-nodpi/glyph_settings.xml | 3 + .../main/res/drawable-nodpi/glyph_share.xml | 3 + .../main/res/drawable-nodpi/glyph_shield.xml | 3 + .../main/res/drawable-nodpi/glyph_star.xml | 3 + .../main/res/drawable-nodpi/glyph_streak.xml | 3 + .../main/res/drawable-nodpi/glyph_sync.xml | 3 + .../res/drawable-nodpi/glyph_timeline.xml | 3 + .../main/res/drawable-nodpi/glyph_trash.xml | 3 + .../res/drawable-nodpi/glyph_trending_up.xml | 3 + .../main/res/drawable-nodpi/glyph_warning.xml | 3 + docs/Engineering_Reference_Manual.md | 6 +- scripts/wiring-scan.sh | 111 ++++++++++++++++++ 51 files changed, 356 insertions(+), 13 deletions(-) create mode 100644 Engineering_Reference_Manual_Plan.md create mode 100644 app/src/main/res/drawable-nodpi/glyph_add.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_attach_money.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_back.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_bell.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_cake.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_calendar.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_camera.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_card_giftcard.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_chat.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_check.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_close.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_copy.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_couple.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_edit.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_eye.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_eye_off.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_fingerprint.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_forward.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_heart.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_heart_outline.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_home.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_hourglass.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_key.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_lock.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_lock_open.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_mic.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_open_in_new.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_palette.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_pause.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_person.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_photo.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_play.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_psychology.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_question_answer.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_refresh.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_send.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_settings.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_share.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_shield.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_star.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_streak.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_sync.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_timeline.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_trash.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_trending_up.xml create mode 100644 app/src/main/res/drawable-nodpi/glyph_warning.xml create mode 100755 scripts/wiring-scan.sh diff --git a/ClaudeQAPlan.md b/ClaudeQAPlan.md index 47f92e8a..5bf4d53a 100644 --- a/ClaudeQAPlan.md +++ b/ClaudeQAPlan.md @@ -117,7 +117,7 @@ confirms + enumerates this; the fix phase applies couple-shared everywhere. are the authoritative state** and survive any compaction — after a summary, **re-read them and continue at the next chunk**. Never pause a run merely because context is getting long; only stop for a true blocker (a denied gated action even with standing auth, or the macOS requirement for iOS). -- **Commit before anything interruptible** so a mid-chunk compaction never loses progress. Keep chunks atomic; if a +- **Checkpoint (save the working-tree MD files + run-state) before anything interruptible** so a mid-chunk compaction never loses progress (the user commits — never run git yourself). Keep chunks atomic; if a chunk is cut off mid-way (e.g., a game session left active), the **session-start ritual recovers it** (clear the stuck session via in-app "End their game", then redo that chunk). Right-sized chunks (see Batch sizing) make this rare. - **Don't pause for "by-design vs bug":** log the ambiguous finding and keep going (don't unilaterally rewrite @@ -305,7 +305,7 @@ State lives in **files**, not memory: path crashed → don't fix by reasoning; reproduce via the real channel + read the stack"). This is how the plan self-improves between rounds — treat the human pointing out a missed bug as a signal the plan had a gap, and close the gap here, not just the bug. -- **Commit cadence**: commit `ClaudeReport.md` + `ClaudeQACoverage.md` after each pass and each chunk. +- **Checkpoint cadence**: save `ClaudeReport.md` + `ClaudeQACoverage.md` + run-state after each pass and each chunk (the **user** commits — never run git yourself; see Guardrails). - **Chunking**: run small chunks (Pass C one screen-group; Pass A one feature), checkpoint after each. - **Session-start ritual**: (1) read run-state header + both MD files; (2) `adb devices` shows **both** emulators online; (3) **installed build == current HEAD** (rebuild+reinstall if unsure — never QA a stale APK); (4) continue @@ -314,14 +314,15 @@ State lives in **files**, not memory: ## Batch sizing — sub-batch each pass to ONE context window (Round-1 calibration) A pass is a **category**, not a unit of work. Execute each pass as **sub-batches (chunks)**, where a chunk = the -**largest coherent unit that reliably finishes AND commits within one context window, with margin**. End every chunk -with a commit + run-state update. If a chunk starts overflowing, split it; if chunks feel trivial, merge them. +**largest coherent unit that reliably finishes AND checkpoints within one context window, with margin**. End every chunk +by saving the MD files + run-state (the user commits — never run git yourself). If a chunk starts overflowing, split it; +if chunks feel trivial, merge them. **Why:** in Round 1, A & D fit as single batches, but B/C/E were too large → got cut off → deferred. Sub-batching -prevents half-done/lost work and gives cleaner per-chunk verification + revertable commits. +prevents half-done/lost work and gives cleaner per-chunk verification + revertable history. Default small: if a chunk requires two-device live driving, screenshots/montage review, logcat checks, or admin/API verification, keep it to **one small route family, one game phase, or one notification type**. A chunk is too large if -it cannot produce a precise coverage update, issue log, and commit before context gets tight. Split before starting +it cannot produce a precise coverage update, issue log, and file-checkpoint before context gets tight. Split before starting rather than leaving a half-tested matrix behind. **Prefer Claude-friendly micro-batches**: smaller chunks let the agent fully inspect screenshots, tap every CTA, vary app states, update files accurately, and avoid shallow "covered" rows. @@ -348,6 +349,11 @@ Context-cost tips: prefer **code/admin-read audits** (cheap) before live UI swee (dark|light pairs) to review many at once; keep one chunk = one TodoWrite focus. ## Guardrails & efficiency +- **⛔ NEVER `git commit` / `git push` — the USER does ALL commits.** This overrides every "commit" verb elsewhere in + this doc: wherever a step says "commit," read it as **"checkpoint = save the working-tree files (`ClaudeReport.md` + + `ClaudeQACoverage.md` + run-state, plus any code/docs)"** and leave the actual `git commit` to the user. Your durable + state lives in those files (they survive compaction), not in a commit you make. Never stage, commit, push, branch, or + amend. - **Never `pm clear` / wipe app data** — breaks the App Check debug token. Pre-pairing QA: sign-out → fresh sign-up. - **Never run `seed/build_db.py`.** Admin seeds/writes, entitlement toggles, and any deploys are **user-authorized per occurrence**. - **By-design vs bug:** if a finding may be intended behavior, **log it and keep going** (don't stop to ask; don't unilaterally rewrite deliberate design — the log captures it). diff --git a/Engineering_Reference_Manual_Plan.md b/Engineering_Reference_Manual_Plan.md new file mode 100644 index 00000000..2b48670a --- /dev/null +++ b/Engineering_Reference_Manual_Plan.md @@ -0,0 +1,92 @@ +# Engineering Reference Manual Update Plan + +Goal: bring `docs/Engineering_Reference_Manual.md` into alignment with the current +relationship-app codebase. Verify every claim, file path, function name, +collection name, and architectural fact. Never assume. + +## Approach + +- **Batch-based.** Each batch covers one major section or a coherent set of + subsections. One agent/turn per batch. +- **Evidence-first.** For every factual claim in the manual, verify against the + repo (grep, read file, run build/test if needed). +- **Log everything.** Each batch updates this plan with findings and + changes made. +- **Ripley coordinates.** Ripley does not code unless necessary; Bishop or + subagents may verify builds/docs. + +## Batches + +### Batch 1 — Front matter + System overview + Repository layout +- Read: `## How to use this document` through `### Shared configuration`. +- Verify all directory paths under `app/src/main/java/app/closer/`, + `functions/src/`, `functions/dist/`, `res/drawable-*`. +- Flag missing or renamed directories/files. +- Update any stale paths or naming. + +### Batch 2 — Authentication, pairing, couples model +- Read: `## Authentication and pairing flow` through `### Key Cloud Functions`. +- Verify auth files, pairing flow files, `couples` collection fields, + recovery phrase implementation. +- Cross-check `firestore.rules` for the rules described. +- Update if code diverges from doc. + +### Batch 3 — E2EE model + Firestore data model +- Read: `## End-to-end encryption model` and `## Firestore data model`. +- Verify crypto files, encryption versions, collection schemas, field names. +- Check `firestore.rules` regex helpers and invariants. +- Update data model tables if collections/fields changed. + +### Batch 4 — Daily question lifecycle + Cloud Functions module +- Read: `## Daily question lifecycle` and `## Cloud Functions`. +- Verify function triggers, handlers, schedules, module responsibilities. +- Cross-check `functions/src/` tree. +- Update if functions were added/removed/renamed. + +### Batch 5 — Firestore security rules +- Read: `## Firestore security rules`. +- Line-by-line verify against `firestore.rules`. +- Note any rules in the file not documented, or documented rules not in file. + +### Batch 6 — Billing + Notifications +- Read: `## Billing` and `## Notifications`. +- Verify RevenueCat integration files, entitlement checks, webhook handler. +- Verify notification classes, quiet hours, deep-link routing. +- Update for quiet-hours server-side suppression if doc still says local-only. + +### Batch 7 — iOS-specific + Build and release +- Read: `## iOS-specific notes` and `## Build and release`. +- Verify iOS project state (is it still broken? still exists?). +- Verify build commands, secrets, ProGuard, Functions deploy commands. +- Update stale commands or iOS status. + +### Batch 8 — Known landmines and recent fixes (cross-cutting) +- Read: `## Known landmines and recent fixes`. +- Verify each listed issue ID and fix matches git history and current code. +- Add any missing recent landmines (e.g., theme scanner, quiet hours server-side). +- Prune obsolete entries. + +### Batch 9 — Final review, TOC update, formatting +- Update `## Table of Contents` if headings changed. +- Run markdown lint / build check if applicable. +- Final pass for consistency. + +## Status tracking + +| Batch | Status | Findings | Changes made | +|---|---|---|---| +| 1 | todo | | | +| 2 | todo | | | +| 3 | todo | | | +| 4 | todo | | | +| 5 | todo | | | +| 6 | todo | | | +| 7 | todo | | | +| 8 | todo | | | +| 9 | todo | | | + +## Notes + +- If a section is found to be mostly correct, still spot-check a few claims. +- If a section is wildly out of date, rewrite it and note the divergence. +- Commit after each batch (per Git Discipline Rules). diff --git a/app/src/main/java/app/closer/ui/dates/DateBuilderViewModel.kt b/app/src/main/java/app/closer/ui/dates/DateBuilderViewModel.kt index 6da4bde7..86d43da7 100644 --- a/app/src/main/java/app/closer/ui/dates/DateBuilderViewModel.kt +++ b/app/src/main/java/app/closer/ui/dates/DateBuilderViewModel.kt @@ -41,10 +41,6 @@ class DateBuilderViewModel @Inject constructor( _uiState.update { it.copy(duration = duration) } } - fun setDateIdeaId(dateIdeaId: String) { - _uiState.update { it.copy(dateIdeaId = dateIdeaId) } - } - fun savePreference() { val state = _uiState.value diff --git a/app/src/main/res/drawable-nodpi/glyph_add.xml b/app/src/main/res/drawable-nodpi/glyph_add.xml new file mode 100644 index 00000000..a15f1c16 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_add.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_attach_money.xml b/app/src/main/res/drawable-nodpi/glyph_attach_money.xml new file mode 100644 index 00000000..6acd4103 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_attach_money.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_back.xml b/app/src/main/res/drawable-nodpi/glyph_back.xml new file mode 100644 index 00000000..a5ca9f4c --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_back.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_bell.xml b/app/src/main/res/drawable-nodpi/glyph_bell.xml new file mode 100644 index 00000000..479d1048 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_bell.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_cake.xml b/app/src/main/res/drawable-nodpi/glyph_cake.xml new file mode 100644 index 00000000..07aa1d6d --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_cake.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_calendar.xml b/app/src/main/res/drawable-nodpi/glyph_calendar.xml new file mode 100644 index 00000000..23626372 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_calendar.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_camera.xml b/app/src/main/res/drawable-nodpi/glyph_camera.xml new file mode 100644 index 00000000..c159f1b6 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_camera.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_card_giftcard.xml b/app/src/main/res/drawable-nodpi/glyph_card_giftcard.xml new file mode 100644 index 00000000..c6b45bf7 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_card_giftcard.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_chat.xml b/app/src/main/res/drawable-nodpi/glyph_chat.xml new file mode 100644 index 00000000..2286c6bb --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_chat.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_check.xml b/app/src/main/res/drawable-nodpi/glyph_check.xml new file mode 100644 index 00000000..bd1b4f45 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_check.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_close.xml b/app/src/main/res/drawable-nodpi/glyph_close.xml new file mode 100644 index 00000000..c27e2e3a --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_close.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_copy.xml b/app/src/main/res/drawable-nodpi/glyph_copy.xml new file mode 100644 index 00000000..d9efdbbd --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_copy.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_couple.xml b/app/src/main/res/drawable-nodpi/glyph_couple.xml new file mode 100644 index 00000000..66f24b61 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_couple.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_edit.xml b/app/src/main/res/drawable-nodpi/glyph_edit.xml new file mode 100644 index 00000000..b11fa12a --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_edit.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_eye.xml b/app/src/main/res/drawable-nodpi/glyph_eye.xml new file mode 100644 index 00000000..88760792 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_eye.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_eye_off.xml b/app/src/main/res/drawable-nodpi/glyph_eye_off.xml new file mode 100644 index 00000000..e4cf1392 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_eye_off.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_fingerprint.xml b/app/src/main/res/drawable-nodpi/glyph_fingerprint.xml new file mode 100644 index 00000000..de5acaee --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_fingerprint.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_forward.xml b/app/src/main/res/drawable-nodpi/glyph_forward.xml new file mode 100644 index 00000000..0ec096ee --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_forward.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_heart.xml b/app/src/main/res/drawable-nodpi/glyph_heart.xml new file mode 100644 index 00000000..d67e6b17 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_heart.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_heart_outline.xml b/app/src/main/res/drawable-nodpi/glyph_heart_outline.xml new file mode 100644 index 00000000..7d40a987 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_heart_outline.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_home.xml b/app/src/main/res/drawable-nodpi/glyph_home.xml new file mode 100644 index 00000000..b281cd63 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_home.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_hourglass.xml b/app/src/main/res/drawable-nodpi/glyph_hourglass.xml new file mode 100644 index 00000000..9afe1aaa --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_hourglass.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_key.xml b/app/src/main/res/drawable-nodpi/glyph_key.xml new file mode 100644 index 00000000..ef9bc27d --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_key.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_lock.xml b/app/src/main/res/drawable-nodpi/glyph_lock.xml new file mode 100644 index 00000000..e89b91cc --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_lock.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_lock_open.xml b/app/src/main/res/drawable-nodpi/glyph_lock_open.xml new file mode 100644 index 00000000..93ed2c1c --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_lock_open.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_mic.xml b/app/src/main/res/drawable-nodpi/glyph_mic.xml new file mode 100644 index 00000000..cfea5f48 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_mic.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_open_in_new.xml b/app/src/main/res/drawable-nodpi/glyph_open_in_new.xml new file mode 100644 index 00000000..aa97fc35 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_open_in_new.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_palette.xml b/app/src/main/res/drawable-nodpi/glyph_palette.xml new file mode 100644 index 00000000..0a5d63b5 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_palette.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_pause.xml b/app/src/main/res/drawable-nodpi/glyph_pause.xml new file mode 100644 index 00000000..9ecb0b19 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_pause.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_person.xml b/app/src/main/res/drawable-nodpi/glyph_person.xml new file mode 100644 index 00000000..e017d36a --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_person.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_photo.xml b/app/src/main/res/drawable-nodpi/glyph_photo.xml new file mode 100644 index 00000000..322220c1 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_photo.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_play.xml b/app/src/main/res/drawable-nodpi/glyph_play.xml new file mode 100644 index 00000000..4f9f4d45 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_play.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_psychology.xml b/app/src/main/res/drawable-nodpi/glyph_psychology.xml new file mode 100644 index 00000000..c8cfd5fa --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_psychology.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_question_answer.xml b/app/src/main/res/drawable-nodpi/glyph_question_answer.xml new file mode 100644 index 00000000..34bc9084 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_question_answer.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_refresh.xml b/app/src/main/res/drawable-nodpi/glyph_refresh.xml new file mode 100644 index 00000000..75114d01 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_refresh.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_send.xml b/app/src/main/res/drawable-nodpi/glyph_send.xml new file mode 100644 index 00000000..b1e80d1b --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_send.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_settings.xml b/app/src/main/res/drawable-nodpi/glyph_settings.xml new file mode 100644 index 00000000..16e63ca2 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_settings.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_share.xml b/app/src/main/res/drawable-nodpi/glyph_share.xml new file mode 100644 index 00000000..64a5f9dc --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_share.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_shield.xml b/app/src/main/res/drawable-nodpi/glyph_shield.xml new file mode 100644 index 00000000..0f1b26c9 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_shield.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_star.xml b/app/src/main/res/drawable-nodpi/glyph_star.xml new file mode 100644 index 00000000..822b4534 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_star.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_streak.xml b/app/src/main/res/drawable-nodpi/glyph_streak.xml new file mode 100644 index 00000000..706fdc1f --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_streak.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_sync.xml b/app/src/main/res/drawable-nodpi/glyph_sync.xml new file mode 100644 index 00000000..2684a3ac --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_sync.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_timeline.xml b/app/src/main/res/drawable-nodpi/glyph_timeline.xml new file mode 100644 index 00000000..f96a89b9 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_timeline.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_trash.xml b/app/src/main/res/drawable-nodpi/glyph_trash.xml new file mode 100644 index 00000000..2a21f796 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_trash.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_trending_up.xml b/app/src/main/res/drawable-nodpi/glyph_trending_up.xml new file mode 100644 index 00000000..bea132f3 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_trending_up.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/drawable-nodpi/glyph_warning.xml b/app/src/main/res/drawable-nodpi/glyph_warning.xml new file mode 100644 index 00000000..d6c9bb18 --- /dev/null +++ b/app/src/main/res/drawable-nodpi/glyph_warning.xml @@ -0,0 +1,3 @@ + + + diff --git a/docs/Engineering_Reference_Manual.md b/docs/Engineering_Reference_Manual.md index b6e97b02..179014aa 100644 --- a/docs/Engineering_Reference_Manual.md +++ b/docs/Engineering_Reference_Manual.md @@ -89,14 +89,14 @@ app/src/main/java/app/closer/ │ ├── analytics/ # Firebase Analytics + Crashlytics wrappers │ ├── billing/ # EntitlementChecker + FirestoreEntitlementChecker │ ├── crash/ # CrashReporter abstraction -│ ├── feature/ # (reserved for feature flags; currently empty — no feature-flag code in repo today) +│ ├── feature/ # (reserved for feature flags; no directory exists today — no feature-flag code in repo) │ ├── navigation/ # AppRoute constants, NavHost, ExternalLinks │ └── notifications/ # AppMessagingService, NotificationHelper, NotificationPermissionHelper, QuietHours, TokenRegistrar ├── crypto/ # E2EE: Tink AEAD, BouncyCastle Argon2id, key stores ├── data/ │ ├── challenges/ # Connection Challenges data sources │ ├── local/ # Room DAOs, DataStore, EncryptedSharedPreferences (RecoveryPhraseStore, SecurePreferencesFactory, SettingsDataStore) -│ ├── questions/ # Question pack data sources (QuestionDao + QuestionJsonParser) +│ ├── questions/ # Question pack data sources (`QuestionJsonParser`) │ ├── remote/ # Firestore data sources, Cloud Functions callable wrappers │ ├── repository/ # Repository implementations │ └── security/ # PlayIntegrityChecker @@ -131,7 +131,7 @@ app/src/main/java/app/closer/ └── wheel/ # Spin the wheel ``` -**Note on the manual's older description**: a `core/security/` package and `data/local/QuestionJsonParser.kt` were documented in earlier revisions of this manual but don't exist in the current source. The auth rate limiter is in `domain/security/AuthRateLimiter.kt`, and the question JSON parser is at `data/questions/QuestionJsonParser.kt`. +**Note on the manual's older description**: a `core/security/` package was documented in earlier revisions of this manual but doesn't exist in the current source. The auth rate limiter is in `domain/security/AuthRateLimiter.kt`, and `QuestionJsonParser` is at `data/questions/QuestionJsonParser.kt` while `QuestionDao` is in `data/local/QuestionDao.kt`. The Android settings package contains: `SettingsScreen`, `SettingsViewModel`, `SettingsVisuals`, `AccountScreen`, `EditProfileScreen` + `EditProfileViewModel`, `AppearanceScreen`, `DeleteAccountScreen`, `NotificationSettingsScreen`, `PrivacyScreen`, `RelationshipSettingsScreen`, `SecurityScreen`, `SubscriptionScreen`. The `SecurityScreen` is biometric-gated for the recovery phrase reveal. diff --git a/scripts/wiring-scan.sh b/scripts/wiring-scan.sh new file mode 100755 index 00000000..db257af1 --- /dev/null +++ b/scripts/wiring-scan.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# +# CloserApp — automated WIRING / dead-feature scanner (Pass N + discovery pre-check) +# +# Catches the "silent dead feature" class that QA found live (N-001 Bucket List, N-002 +# Date Builder): a feature looks like an empty/initial state but is actually non-functional +# because a required id is never wired, a setter is never called, or saved data is never read. +# +# ⛔ CLAUDE: This is a LIVING tool — IMPROVE IT whenever you discover a new dead-wiring / orphan +# failure mode. Add the new grep, keep the script self-contained + runnable from the project +# root, write findings to stdout + SCAN_OUTPUT, and update this header with what you added. +# Do not remove an existing check unless it is provably wrong (note why in the header). +# +# Usage: +# ./scripts/wiring-scan.sh > /tmp/claude-wiring-scan-$(date +%Y%m%d).md +# cat /tmp/claude-wiring-scan-$(date +%Y%m%d).md +# +# Tiers: +# 🔴 CRITICAL — a `fun setX(...)` in a *ViewModel.kt with ZERO callers. The screen/nav never +# pushes the value, so any op gated on it silently no-ops (N-001 class). +# 🟠 MAJOR — a repository/data-source READ method (`fun observe*/get*/load*`) with no caller +# in `ui/`. Data the app can write but never displays → orphan feature (N-002 class). +# 🟡 REVIEW — a `if (x.isEmpty()/== null) return` / `?: return` bail-guard inside a *ViewModel. +# Legitimate, BUT confirm something actually provides `x` — an un-provided guard is +# exactly how a feature goes silently dead. Verify each by persisting real data and +# reading it back from Firestore (admin), not by trusting the empty-state render. +# +# Findings are HINTS, not proofs — a flagged item can be intentional (e.g. a setter used only in a +# @Preview, or a read method genuinely pending UI). Confirm each against live behavior + ground truth. +# +set -uo pipefail + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SRC_DIR="$PROJECT_ROOT/app/src/main/java/app/closer" +UI_DIR="$SRC_DIR/ui" +SCAN_OUTPUT="${1:-/tmp/claude-wiring-scan-$(date +%Y%m%d).md}" +: > "$SCAN_OUTPUT" + +log() { echo "$1" | tee -a "$SCAN_OUTPUT"; } + +crit=0; major=0; review=0 + +log "# Wiring / dead-feature scan — $(date '+%Y-%m-%d %H:%M')" +log "" +log "> Hints, not proofs. Confirm each against live behavior + a Firestore admin read." +log "" + +# ── Tier 1: dead setters (CRITICAL) ─────────────────────────────────────────── +log "## 🔴 CRITICAL — ViewModel \`setX(...)\` with no caller (N-001 class)" +log "" +while IFS= read -r decl; do + file="${decl%%:*}" + name="$(echo "$decl" | grep -oE 'fun set[A-Z][A-Za-z0-9]*' | head -1 | sed 's/^fun //')" + [ -z "$name" ] && continue + # callers = references to `name(` or `::name` anywhere under SRC, minus the declaration itself + callers="$(grep -rEn "(\.|::| )${name}\(|::${name}\b" "$SRC_DIR" 2>/dev/null | grep -v "fun ${name}(" | grep -cv '^$')" + if [ "${callers:-0}" -eq 0 ]; then + log "- 🔴 \`${name}()\` — **no callers** — ${file#$PROJECT_ROOT/}" + crit=$((crit+1)) + fi +done < <(grep -rEn 'fun set[A-Z][A-Za-z0-9]*\(' "$SRC_DIR" --include=*ViewModel.kt 2>/dev/null) +[ "$crit" -eq 0 ] && log "- none ✅" +log "" + +# ── Tier 2: orphan readers (MAJOR) ──────────────────────────────────────────── +log "## 🟠 MAJOR — repository/data-source read method never called from \`ui/\` (N-002 class)" +log "" +# Scan REPOSITORY INTERFACES only (*Repository.kt, which the glob excludes *RepositoryImpl.kt +# + *DataSource.kt) — those are the read entry points a VM/screen would call. A repo read method +# with no ui/ caller means the app can fetch the data but no screen ever shows it (N-002). +while IFS= read -r decl; do + file="${decl%%:*}" + name="$(echo "$decl" | grep -oE 'fun (observe|get|load)[A-Z][A-Za-z0-9]*' | head -1 | sed 's/^fun //')" + [ -z "$name" ] && continue + ui_callers="$(grep -rEn "(\.|::| )${name}\(|::${name}\b" "$UI_DIR" 2>/dev/null | grep -cv '^$')" + if [ "${ui_callers:-0}" -eq 0 ]; then + log "- 🟠 \`${name}()\` — **no \`ui/\` caller** (written data may never be displayed) — ${file#$PROJECT_ROOT/}" + major=$((major+1)) + fi +done < <(grep -rEn 'fun (observe|get|load)[A-Z][A-Za-z0-9]*\(' "$SRC_DIR" --include=*Repository.kt 2>/dev/null) +[ "$major" -eq 0 ] && log "- none ✅" +log "" + +# ── Tier 3: silent bail-guards in ViewModels (REVIEW) ───────────────────────── +log "## 🟡 REVIEW — \`if (x.isEmpty()/==null) return\` / \`?: return\` bail-guards in ViewModels" +log "" +log "Each is a point where the feature silently does nothing if state was never initialized." +log "Confirm something provides the value (persist real data → read it back via admin)." +log "Auth-presence guards (\`currentUserId ?: return\`) are filtered out — they're never the wiring gap;" +log "the risky ones gate on a STATE field a \`setX\`/resolver is supposed to populate (e.g. coupleId)." +log "" +while IFS= read -r hit; do + log "- 🟡 ${hit#$PROJECT_ROOT/}" + review=$((review+1)) +done < <(grep -rEn 'if \([a-zA-Z0-9_.]+\.(isEmpty\(\)|isBlank\(\))\) return|[a-zA-Z0-9_.]+ \?: return\b' "$SRC_DIR" --include=*ViewModel.kt 2>/dev/null \ + | grep -viE 'currentUser|currentUserId|authRepository|FirebaseAuth|firstOrNull|\.find ?\{|getOrNull') +[ "$review" -eq 0 ] && log "- none" +log "" + +log "## Summary" +log "" +log "| Tier | Count |" +log "|---|---|" +log "| 🔴 CRITICAL (dead setters) | $crit |" +log "| 🟠 MAJOR (orphan readers) | $major |" +log "| 🟡 REVIEW (bail-guards) | $review |" +log "" +log "_Record these counts in ClaudeQACoverage.md under Pass N before driving the interactive features._" + +# Exit non-zero only on CRITICAL so CI/automation can gate on it. +[ "$crit" -gt 0 ] && exit 1 || exit 0