Commit Graph

92 Commits

Author SHA1 Message Date
null 5e292e66ea docs(manual): batch 4 review — DOW mode table was partial (missed Saturday)
The server-authoritative mode-aware deterministic selection sub-section
listed the DOW -> mode map as:
  Monday mode_soft_monday, Tuesday mode_snack_mission, ..., Sunday
  mode_tiny_date_night

But the source-of-truth WEEKDAY_MODE_TAGS table in
functions/src/questions/assignDailyQuestion.ts has 7 entries, one per
weekday:
  0 Sunday    mode_tiny_date_night   (Slow Burn Sunday)
  1 Monday    mode_soft_monday       (Mood Check Monday)
  2 Tuesday   mode_snack_mission     (Tiny Win Tuesday)
  3 Wednesday mode_no_phone_moment   (Real One Wednesday)
  4 Thursday  mode_laugh_reset       (Laugh It Off Thursday)
  5 Friday    mode_flirty_friday     (Flirty Friday)
  6 Saturday  mode_weekend_side_quest (Side Quest Saturday)

Saturday was missing. Replaced the partial listing with the full
7-entry table, the constant name, and a note that the map is also
unit-tested (assignDailyQuestion.test.ts). Future reader can now grep
the mode tag against both files at once.

Other Batch 4 claims verified clean:
- Schedule '0 23 * * *' America/Chicago, memory 512MiB, timeoutSeconds 300
  in assignDailyQuestion source - all match.
- Document shape: questionId, date, assignedAt, expiresAt - all match the
  create() payload (assignedAt is serverTimestamp, expiresAt is
  timestampAt6PmCst(nextDay)).
- PAGE_SIZE = 300, ordered by __name__, startAfter pagination - matches.
- The daily_question allow create rule uses isCoupleKeyAnswerCreate OR
  isSealedAnswerCreate - matches the manual's 'must match one of two
  shapes' claim.
- The secure/{doc} read rule uses the partner-has-also-answered exists()
  check - matches the Reveal flow claim.
- isSealedThreadAnswerCreate / Update have NO answerDate and NO
  isRevealed field - matches the Thread questions claim.
2026-07-08 23:22:47 -05:00
null 0af6f24ab8 docs(manual): batch 3 review — Argon2id memory was 46080 KiB but the code is 47104
The Argon2id parameter block said:
  - memory: 46 MiB (46080 KiB)
  - iterations: 3
  - parallelism: 1

But the source constant in RecoveryKeyManager.kt is:
  private const val ARGON2_MEMORY_KB = 46 * 1024

46 * 1024 = 47104, not 46080 (a slipped digit). 46080 KiB would be
45 MiB. The iOS-side docstring in CoupleEncryptionManager.swift
already says 46 MiB = 47104 KiB, so this is the Android-side drift.

Replaced the parameter block with the source-of-truth constant names
(ARGON2_MEMORY_KB, ARGON2_ITERATIONS, ARGON2_PARALLELISM) and the
correct KiB value (47104) so the next reader can grep the code.

Other Batch 3 claims verified clean:
- Encryption version table: EncryptionVersion.STRICT=2, acceptInviteCallable
  hardcodes 2, throws if any of wrappedCoupleKey/kdfSalt/kdfParams is null.
- Tink AEAD wire formats: enc:v1:base64, sealed:v1:urlsafe-base64-no-padding,
  keybox:v1:urlsafe-base64-no-padding, pub:v1:urlsafe-base64-no-padding,
  sha256:urlsafe-base64-no-padding (43 chars). All match the source constants.
- AAD: FieldEncryptor uses coupleId; SealedAnswerEncryptor uses
  coupleId|questionId|userId; both match.
- ECIES P-256: UserKeyManager uses
  HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM;
  ReleaseKeyEncryptor contextInfo is coupleId|questionId|senderUserId|recipientUserId.
- All 5 firestore.rules regex helpers match the manual's reference table.
- wrapReleaseKeyCallable reads the recipient public key from
  users/{uid}/devices/primary (verified in function source).
- CoupleKeyStore persists Tink keyset handles in EncryptedSharedPreferences
  (Keystore-backed) via SecurePreferencesFactory.
2026-07-08 23:21:35 -05:00
null 1b36eba692 docs(manual): batch 2 review — recovery phrase '256-word list' was wrong (it's 248)
The Recovery phrase flow said RecoveryKeyManager.generateRecoveryPhrase()
draws from a 256-word list. Verified the actual list size in
RecoveryKeyManager.kt: the hard-coded WORDLIST array has 248 entries
(python re.findall over the array literal), and the iOS wordlist file
iphone/Closer/Crypto/Resources/wordlist.txt is 247 lines (last word
'real' with no trailing newline, so 248 entries). The '256' is also
wrong in the inline comment in RecoveryKeyManager.kt - a pre-existing
comment bug from before the R24 iOS port (IOS_E2EE_STATUS.md notes the
iOS SPEC.md originally said 256 too, corrected in 922364f). The Android
side never got the same comment fix.

Manual now says 248 with the source-of-truth pointers, and computes
the entropy as 248^10 (a quick sanity check) so the next reader doesn't
trust the wrong number on either side.

Other Batch 2 claims verified clean:
- All 5 Android files in the 'Key Android files' list exist.
- All 2 Cloud Functions files in the 'Key Cloud Functions' list exist.
- Rate limit: 1h window, 10 max, 25h TTL on invite_attempts - all match
  ACCEPT_RATE_LIMIT_WINDOW_MS / ACCEPT_RATE_LIMIT_MAX / ACCEPT_ATTEMPT_TTL_MS
  in acceptInviteCallable.ts and the fieldOverrides entry in
  firestore.indexes.json.
- Couples doc model fields (id, userIds, inviteCode, createdAt,
  streakCount, lastAnsweredAt, currentQuestionId, activePackId,
  encryptionVersion, wrappedCoupleKey, kdfSalt, kdfParams) all match
  the create() payload in acceptInviteCallable.ts. createdAt uses
  FieldValue.serverTimestamp() (manual says 'server-side' - correct).
- EncryptionVersion.STRICT = 2 in EncryptionVersion.kt.
2026-07-08 23:20:16 -05:00
null ef5a2331fd docs(manual): batch 1 review — iOS platform row 'E2EE not yet implemented' was stale
The Three platform split table at the top of the manual said iOS
'E2EE cross-compatibility not yet implemented' even though the iOS
E2EE section below it (and IOS_E2EE_STATUS.md) clearly state it is
code-complete for the schemaVersion 2 (couple-key) daily-answer path.
The schemaVersion 3 sealed-answer path is the part that is
infrastructure-gated (paired-CI vector run + macOS end-to-end).

Replaced the row text with a one-liner that points to the existing
iOS E2EE gap sub-section so future readers don't get the wrong first
impression from the overview.

Batch 1 of the Phase 3 plan (Engineering_Reference_Manual_Plan.md).
Repository layout Android/iOS/Cloud Functions all verified against
the live source - no other drift in this batch.
2026-07-08 23:18:33 -05:00
null 6f4f98f0ad docs(store): sharpen privacy promise in README banner 2026-07-08 23:11:36 -05:00
null d31b58d238 docs(manual): review pass — missing dirs + 3 notif prefs + B6c/B6d mix-up
After pushing the Phase 2 sync, evidence-first review against the live
repo caught:

- Repository layout (Android) was missing directories that have shipped
  since v0.2.1: widget/ (Glance Today, R29), core/firebase/, core/media/,
  data/backup/ (R24 E2EE backup + partner-assist), data/local/{converters,
  entity,mapper} subdirs, data/security/, domain/usecase/ (resolver +
  GameSessionManager + SoloAnswerMigrator), top-level notifications/
  package, and ui/{recap,messages,questions}/ + components/ subdirs.
- Repository layout (iOS) was missing Crypto/Resources/ (wordlist) and
  the Crypto/ design notes (SCHEMA_VERSION_DECISION.md, SPEC.md).
- User doc field list + per-collection enforcement were missing the 3
  R20 notif preferences: notifDailyReminder, notifStreakReminder,
  notifPromotional. Verified all 5 are mirrored by
  FirestoreUserDataSource.updateNotificationPrefs() and listed in the
  firestore.rules user-doc allowlist.
- One copy fix: 'The B6d split of onGameSessionUpdate' -> 'The B6c
  split' (B6c did the part-finished split; B6d was the logger finish).

Anchors verified clean (30/30). DEVELOPMENT_LOG.md is gitignored so
the local review notes stay on this box.
2026-07-08 22:10:40 -05:00
null 1242799001 docs(store): rename marketing assets to Closer Couples 2026-07-08 22:01:10 -05:00
null 213cfddb16 docs(manual): sync Engineering Reference Manual with post-R30 / v2-functions codebase
- Cloud Functions: rewrite the module tree for the v2 migration (B0-B6d,
  2026-07-08); add options.ts (global v2 setGlobalOptions, Cloud Run CPU
  quota workaround), log.ts, the shared push/quietHours/idempotency/
  pruneTokens/time infra under notifications/, releaseKey/, backup/,
  the dates/onDate* triggers, couples/aggregateOutcomes, and the new
  sendStreakReminder + sendThinkingOfYouCallable. Replace the single
  onGamePartFinished with the four per-game part-finished triggers
  shipped in B6c. Note the webhook is not deployed (RevenueCat project
  not yet created; export commented out in functions/src/index.ts).
- Daily question lifecycle: replace the 'picks a random' description
  with the new server-authoritative, mode-aware, deterministic picker
  that mirrors the client's DailyModeResolver; add a Server-authoritative
  sub-section with the frozen DOW -> mode map and the daily_fun_mc
  exclusion. Note the couple-scan pagination + unseeded-pool skip.
- Billing: add the Purchases.logIn(firebaseAuth.currentUser!!.uid)
  identity link (commit b99a8338) and the typed BillingException mapping.
  Cross-link to the Webhook reliability section for the not-deployed state.
- iOS: fix the Repository layout iOS Crypto/ block (R24 E2EE code ships
  in it; no longer 'intentionally empty'); correct the 'pairing from iOS
  fails' claim (works for schemaVersion 2 path; schemaVersion 3 is
  infrastructure-gated per IOS_E2EE_STATUS.md); correct the 'iOS couples
  have no recovery path' claim (R24 batch 2 added iOS recovery phrase).
- TOC + anchors: add the new sub-anchors; fix three pre-existing broken
  anchors (r10, ios-android-sealed-answer-bridge, recovery-phrase-change
  desync). 30/30 anchors verified clean with a GFM slug checker.
- New landmines: BANNER-LIFE-001 (R30 game banner lifecycle; the B6c
  per-game split means a new game also needs a per-game monitor hook)
  and FUNCTIONS-V2-DEPLOY (2nd-gen deploy / CPU-quota / Eventarc
  propagation pattern, the 'Changing from an HTTPS function to a
  background triggered function' error and the launch-time quota
  increase to restore 1 vCPU + concurrency 80).
- Engineering_Reference_Manual_Plan.md: add Phase 2 status entry.
2026-07-08 21:56:44 -05:00
null b47302d6b7 docs(readme): refresh daily question screenshots 2026-07-08 14:53:12 -05:00
null 5013c2cd09 docs: update standardization review to completed state
Records the applied standardizations (state collection, whole-data-layer
Tasks→await, version catalog, TS payload typing, 7/8 ViewModel-Firebase
extractions) and the four deliberately-scoped follow-ons (HomeViewModel metadata
listeners, color tokens, Functions v2, catch-unknown) with the reason each needs
its own verification loop rather than a broad sweep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:19:33 -05:00
null 39fbd943ff docs: standardization & modernization review
Grounded review of the Android app / functions / build with measured
inconsistencies, what was standardized this session (collectAsStateWithLifecycle;
Firebase Tasks→await subset), and risk-assessed recommendations for the larger
items (finish Tasks→await, version catalog, ViewModel Firebase extraction,
Functions v2, color tokens, TS types).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:36:59 -05:00
null a79db9474b docs(crypto): key-storage migration design (design-only, gated)
Design for moving off the deprecated androidx.security:security-crypto to
Tink Android-Keystore-backed storage, without ever losing the couple key.
Covers: the load-bearing hazard (SecurePreferencesFactory.reset() silently
WIPES the couple key on any read failure) which must be removed first;
lazy dual-read + re-wrap + verify-then-clean migration; fail-closed (recover,
never delete) failure matrix; consumer ordering (couple key last); staged RC
rollout + content-free telemetry; test plan; open questions for the owner.

No implementation ships until the owner approves this design (Batch 5.1 gate).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:08:52 -05:00
null 55699e17ed feat: security hardening, CI, analytics, invite deep links, solo mode, weekly recap
Roadmap phases 0-3.1 (see plan). Verified: unit tests, functions tests,
firestore rules 119/119, live emulator smokes.

Security + CI:
- Move App Check debug token out of committed build.gradle.kts to
  local.properties (secret() resolver: local.properties -> -P -> env);
  admin service-account key relocated outside the repo.
- Add GitHub Actions (android unit/scan/gitleaks, backend functions +
  rules emulator via emulators:exec) with a CI google-services.json stub
  and a reviewed .gitleaksignore baseline.
- Fix firestore rules tests to the current deployed contract (was 108/118,
  now 119/119).

Analytics + consent:
- FirebaseRetentionAnalytics behind a fail-safe composite sink, single-
  sourced hashing (AnalyticsHashing), Settings -> Privacy opt-out toggle
  gating Firebase + the sink, and the ~11 missing event call sites.
- NoPlaintextInAnalyticsTest guards the content-free rule at build time.

Funnel:
- Invite deep links (https App Link + closer:// fallback), JoinLink parser,
  PendingJoinCodeStore, prefilled/already-paired pairing, richer share text.
- Solo pre-pairing: UnpairedLockedCard on Play, SoloAnswerMigrator + consent
  dialog moving pre-pairing answers into Couple Lore.

Weekly recap:
- WeeklyRecapScreen driven by the existing generator from local answer data,
  Home card rewired, content-free shareable card.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:33:38 -05:00
null f68cab5cf2 feat: signup flow, age gate, user model updates, how well screen, game prompt banner 2026-07-02 02:42:55 -05:00
null d49d67ecbd docs: add reveal-ready brand art + screenshot 2026-07-01 02:55:24 -05:00
null 18490f990e docs: update home screenshots (ready + your-turn states) 2026-07-01 02:19:57 -05:00
null 2ecff95c12 docs: update home-dark screenshot 2026-07-01 01:50:54 -05:00
null 7aa72532b7 docs: update home-dark screenshot 2026-07-01 00:21:54 -05:00
null 38eae8f915 docs: R25 coverage entries, instrumented test landmine warning, tokenized snapshot URL note 2026-06-30 23:33:54 -05:00
null 4773570745 docs: update ClaudeReport (R24-d/c) and Engineering_Reference_Manual (keybox phrase envelope) 2026-06-30 21:25:00 -05:00
null 1e9f8b97bc docs: update Future.md, ClaudeQAPlan.md, ClaudeReport.md, ClaudeiOSPlan.md, Engineering_Reference_Manual.md for R24 backup/restore 2026-06-30 20:43:34 -05:00
null 968ab563a0 docs: add R23-DQ-001 entry to Engineering Reference Manual 2026-06-30 19:06:18 -05:00
null 1159d679b0 docs(date-memories): update glyph README with date_replay count 2026-06-30 18:15:09 -05:00
null 1ea447fcd0 docs(date-memories): add illustration_date_memories_empty source assets 2026-06-30 18:15:07 -05:00
null d2ab0da87e docs(date-memories): add glyph_date_replay source assets 2026-06-30 18:15:05 -05:00
null 2119792cca Revert "feat(date-memories): add glyph_date_replay + illustration_date_memories_empty assets (batch 7/8)"
This reverts commit 067155c108.
2026-06-30 18:13:00 -05:00
null 7cc2e78cfb Revert "docs(date-memories): update QAPlan, Report, iOS parity plan, and glyph README (batch 8/8)"
This reverts commit 6179a46c96.
2026-06-30 18:13:00 -05:00
null 6179a46c96 docs(date-memories): update QAPlan, Report, iOS parity plan, and glyph README (batch 8/8) 2026-06-30 16:52:09 -05:00
null 067155c108 feat(date-memories): add glyph_date_replay + illustration_date_memories_empty assets (batch 7/8) 2026-06-30 16:52:04 -05:00
null 2a5c40508e feat(notifications): QuietHoursManager + NotificationSettingsScreen rewrite, Cloud Functions (streakReminder, quietHours, reengagement, gameRetention), UserRepository E2EE wiring, SettingsDataStore, firestore rules, wiring-scan 2026-06-30 00:38:06 -05:00
null f6291e1f2e feat(home): HomeScreen rewrite, HomePriorityEngine polish, CoupleRepository E2EE wiring, OutcomeCheckInDialog, YourProgress, MemoryLane, settings/pairing/paywall/play/wheel/question screens cleanup, brand illustrations, QA docs 2026-06-29 16:51:46 -05:00
null 912b8c8093 feat(onboarding): RecoveryKeyManager fix, OnboardingScreen polish, build.gradle bump, Future.md planning update 2026-06-29 13:01:08 -05:00
null b5b8ad8df9 feat(games): GameSessionManager cleanup, QuestionSessionRepositoryImpl fixes, HomeViewModel game-state wiring, QA docs 2026-06-29 12:20:07 -05:00
null f6885b5fa4 docs(readme): revamped screenshot grid (dark mode), updated tagline and badges 2026-06-29 11:18:02 -05:00
null 582aefcec2 feat(tools): capture_android_canonical_vectors.sh for paired-CI fixture filling; sync Engineering Manual for wrapReleaseKeyCallable + iOS Keychain 2026-06-28 17:31:30 -05:00
null d404301579 brand: update glyph_connection_challenge preview PNG + contact sheet + ClaudeBrandingReview 2026-06-28 17:19:17 -05:00
null 5c64f69754 brand: SVG restructure of glyph_connection_challenge (g→paths, added rect) 2026-06-28 17:09:23 -05:00
null 4215563873 brand: update glyph_connection_challenge + add glyph_closer_heart_keyhole 2026-06-28 17:09:02 -05:00
null 2d77786254 brand: refresh dark-variant illustrations (couple_history, couple_onboarding, tonight_partner_prompt) + dark contact sheet 2026-06-28 16:48:37 -05:00
null cdf84352d6 docs(screenshots): recapture 02-login.png on new emulator-5558 2026-06-28 16:35:20 -05:00
null b9828b60c5 brand: refresh dark-variant illustrations (couple_paywall, partner_activation, together_empty) and dark contact sheet 2026-06-28 16:34:51 -05:00
null 736885c103 docs: update README and Engineering Manual — auth uses Credential Manager, iOS pairing blocked, add scripts/ layout, new screenshot placeholder 2026-06-28 12:55:24 -05:00
null faa0d9007f docs: consolidate Future backlog, update ClaudeQAPlan/ClaudeReport, note FUTURE.md removal in Engineering Manual 2026-06-28 12:45:54 -05:00
null f927097d67 brand: update dark-theme illustration and pack-art night assets 2026-06-28 12:45:15 -05:00
null 954aab4cd2 brand: add generated glyph assets + illustration exports, allow generated-art in git 2026-06-28 11:30:12 -05:00
null 186b40546b docs(manual): Batch 9 — fix TOC nesting, broken anchor, and stale iOS claim in repository layout 2026-06-28 11:14:37 -05:00
null df2837dc06 docs(manual): Batch 8 — update theme landmine entry (C-ART-EDGE-002 closed, theme scanner mandatory) 2026-06-28 11:13:21 -05:00
null eb78b920a4 docs(manual): Batch 7 — correct iOS E2EE gap details and ProGuard description 2026-06-28 11:12:15 -05:00
null 8ce99e197f art 2026-06-28 11:10:46 -05:00
null e4175ebb52 docs(manual): Batch 6 — correct Billing webhook flow, add CouplePremiumChecker, fix quiet-hours and notification_queue claims 2026-06-28 11:10:08 -05:00