Commit Graph

3 Commits

Author SHA1 Message Date
null eb4bab0b90 perf(functions): B6b bound the unbounded couple scanners (#10)
assignDailyQuestion and aggregateOutcomeStats previously did an unbounded
db.collection('couples').get() (loading every couple into memory), and aggregate did a
serial outcomes.get() per couple (O(couples) round-trips). Both now paginate the couple
scan (orderBy __name__ + startAfter, 300/200 per page — no custom index needed):

- assignDailyQuestion: each page's create() writes fan out with the burst bounded to a page
  instead of all couples at once; ALREADY_EXISTS stays the idempotent no-op.
- aggregateOutcomeStats: reads each page's outcomes in parallel instead of serially.
  couples.length still counts every couple, so the aggregate windows + totalCouples are
  unchanged (pure aggregate() helper and its tests untouched).

This is the one behavior-touching improvement flagged in the plan; the 512MiB/300s resource
options from B2 remain the safety net. Build clean; 70 tests green. dist rebuilt.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 00:05:32 -05:00
null 6681bf1518 refactor(functions): B2 migrate 8 scheduled functions to v2 + harden
Migrate all scheduled jobs off functions.pubsub.schedule().onRun() to
firebase-functions/v2/scheduler onSchedule({ schedule, timeZone, ...opts }, handler):
sendChallengeDayReminders, unlockDueMemoryCapsules, sendDailyQuestionProactiveReminder,
sendStreakReminder, sendReengagementReminder, assignDailyQuestion (scheduled export),
aggregateOutcomeStats, scheduledOutcomesReminder.

Hardening folded in:
- Fan-out isolation: Promise.all → Promise.allSettled in dailyQuestionReminder (outer+inner),
  reengagement, gameRetention (both jobs), scheduledOutcomesReminder — one bad couple can no
  longer abort a whole run. streakReminder / assignDailyQuestion already isolated.
- Resource options: assignDailyQuestion + aggregateOutcomeStats memory 512MiB + timeout 300s
  (they iterate all couples); the four fan-out reminders get timeout 180s.
- Adopt shared sendPushToUser()/logger everywhere; remove five copied getUserTokens() and the
  copied send/prune blocks (no plaintext token logging remains here).
- Consolidate duplicated date/time helpers into notifications/time.ts (chicagoDateKey, toMillis),
  replacing streakReminder's + scheduledOutcomesReminder's per-file copies.

assignDailyQuestion.ts callable export stays v1 for now (migrates in B3); its tested CST helpers
are untouched. Scanner pagination for assignDailyQuestion/aggregateOutcomes is deferred to B6.

Build clean; 70 tests green (tested pure helpers preserved). dist rebuilt. Still on v5.1.1.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-07 23:50:59 -05:00
null eeac3c9383 build(functions): compile dist for outcome aggregation
Tracked dist output rebuilt to match src (aggregateOutcomeStats export +
aggregateOutcomes module), keeping the deployed bundle in sync with source.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-06 21:10:02 -05:00