docs(manual): batch 12 review - restored A-201 landmine header

The A-201 landmine entry's '### A-201 - ...' heading got dropped during
the Phase 2 sync (213cfddb). The Symptom/Fix/Re-introduction risk
content was still there but visually merged into the previous
FUNCTIONS-V2-DEPLOY landmine's tail. Restored the heading so the
TOC structure (each landmine is a h3) and the markdown renderer both
produce a clean section break.

Other Batch 12 claims verified clean (spot-check):
- R24-BACKUP: data/backup/{BackupManager,BackupRestoreManager,RestoreManager}.kt
  all exist.
- INVITE-DEEPLINK: PendingInviteStore.kt and PendingJoinCodeStore.kt
  both exist in data/local/; the two-store distinction is real.
- R23-DQ-001, B-ABANDON-001, Recovery-phrase change desync, N-001/N-002,
  M-001, N-NOTIF-001, C-DARK-UI-001, C-ART-EDGE-002, Premium-unlock
  modal, F-RACE-001, E-GAME-001/002/003, C-NAV-001, C-SEC-001,
  Back-stack C-NAV-002/003, C-HOME-001, Splash-exit crash, Deep-link,
  BANNER-LIFE-001, FUNCTIONS-V2-DEPLOY, Theme-variant (C-DARKART-001,
  C-ART-EDGE-001/002 closed; theme scanner now mandatory): all
  cross-checked against current source. No file pointers broken.
This commit is contained in:
null 2026-07-08 23:32:49 -05:00
parent b3725463ec
commit 80751f82fb
1 changed files with 2 additions and 0 deletions

View File

@ -1458,6 +1458,8 @@ OOB code = `truncate6(SHA-256(pubkey ‖ nonce))`.
**Root cause**: an orphaned `https` service (from a partial deploy or a previous attempt) is blocking the new background trigger from being created under the same name. The 2nd-gen quota was the proximate cause of the *initial* deploy failure (Cloud Run CPU quota couldn't fit ~35 services at v2's default 1 vCPU/instance; container healthchecks failed with *"Quota exceeded for total allowable CPU per project per region"*) - `functions/src/options.ts` pins `cpu: 'gcf_gen1'`, `concurrency: 1`, `maxInstances: 5` as the workaround. **Root cause**: an orphaned `https` service (from a partial deploy or a previous attempt) is blocking the new background trigger from being created under the same name. The 2nd-gen quota was the proximate cause of the *initial* deploy failure (Cloud Run CPU quota couldn't fit ~35 services at v2's default 1 vCPU/instance; container healthchecks failed with *"Quota exceeded for total allowable CPU per project per region"*) - `functions/src/options.ts` pins `cpu: 'gcf_gen1'`, `concurrency: 1`, `maxInstances: 5` as the workaround.
**Fix / deploy pattern**: when the "Changing from an HTTPS function to a background triggered function" error appears, `firebase functions:delete <stray-name>` then redeploy. Diagnose with `firebase functions:list` - healthy Firestore triggers show `google.cloud.firestore.document.v1.*` in the trigger column; strays show `https`. For the Eventarc propagation race, wait 2-3 minutes and retry. **At launch**: request the Cloud Run CPU quota increase (console → IAM & Admin → Quotas, us-central1), then drop `cpu`/`concurrency` from `options.ts` to restore 1 vCPU + concurrency 80. **Fix / deploy pattern**: when the "Changing from an HTTPS function to a background triggered function" error appears, `firebase functions:delete <stray-name>` then redeploy. Diagnose with `firebase functions:list` - healthy Firestore triggers show `google.cloud.firestore.document.v1.*` in the trigger column; strays show `https`. For the Eventarc propagation race, wait 2-3 minutes and retry. **At launch**: request the Cloud Run CPU quota increase (console → IAM & Admin → Quotas, us-central1), then drop `cpu`/`concurrency` from `options.ts` to restore 1 vCPU + concurrency 80.
**Re-introduction risk**: a deploy that changes a function's *type* (callable → scheduled → trigger) under the same name WILL fail. Plan the rename + 2-step delete/redeploy if you need to refactor a function's surface. **Re-introduction risk**: a deploy that changes a function's *type* (callable → scheduled → trigger) under the same name WILL fail. Plan the rename + 2-step delete/redeploy if you need to refactor a function's surface.
### A-201 - Date Match premium ideas ungated (a badge is NOT a gate)
**Symptom**: free users could view, like and match `isPremium` date ideas with no paywall. `DateMatchRepositoryImpl.getDateIdeas()` returned `DateIdeaSeed.all` with no entitlement filter; `DateMatchViewModel` had no `CouplePremiumChecker`; `DateMatchScreen` rendered only a cosmetic `PremiumBadge()`. (Server still blocked real premium self-grant, so only premium *content* leaked, not the entitlement.) **Symptom**: free users could view, like and match `isPremium` date ideas with no paywall. `DateMatchRepositoryImpl.getDateIdeas()` returned `DateIdeaSeed.all` with no entitlement filter; `DateMatchViewModel` had no `CouplePremiumChecker`; `DateMatchScreen` rendered only a cosmetic `PremiumBadge()`. (Server still blocked real premium self-grant, so only premium *content* leaked, not the entitlement.)
**Fix (R12)**: `DateMatchViewModel` injects `CouplePremiumChecker`; `swipeCurrent` intercepts LOVE/MAYBE on a premium idea when neither partner is premium → emits `paywallRequired``DateMatchScreen` navigates to the Paywall; SKIP still passes; the deck stays on the card. Mirrors the established [gate pattern](#premium-gated-features-and-gate-pattern). **Fix (R12)**: `DateMatchViewModel` injects `CouplePremiumChecker`; `swipeCurrent` intercepts LOVE/MAYBE on a premium idea when neither partner is premium → emits `paywallRequired``DateMatchScreen` navigates to the Paywall; SKIP still passes; the deck stays on the card. Mirrors the established [gate pattern](#premium-gated-features-and-gate-pattern).
**Re-introduction risk / lesson**: a feature can ship an `isPremium` content flag + a `PremiumBadge` with **no enforcement at all**. When adding premium content, wire a real `CouplePremiumChecker` gate (filter OR paywall-on-interaction) - a badge is a label, not a lock. Audit by **trying to USE premium content as a free user**, not by grepping for checker usages (which only finds the features that already have one). **Re-introduction risk / lesson**: a feature can ship an `isPremium` content flag + a `PremiumBadge` with **no enforcement at all**. When adding premium content, wire a real `CouplePremiumChecker` gate (filter OR paywall-on-interaction) - a badge is a label, not a lock. Audit by **trying to USE premium content as a free user**, not by grepping for checker usages (which only finds the features that already have one).