Work / Charades / Wiki / Concepts
persisted-state
Conceptverified 2026-10-30
persisted-state
selectedPackIds is authoritative user state, not derived output. On rehydrate it is
only pruned of packs that are no longer valid or owned. It must never be recomputed from
the packs the user happens to own, which is what used to discard their per-pack choices on
every launch.
A fresh install selects only family-starter (DEFAULT_SELECTED_PACK_IDS in
src/lib/pack-selection.ts), which is also the fallback when pruning leaves nothing. Every
later launch restores the saved selection through the store's merge, minus any pack no
longer owned.
Store version is 5 (v4 → v5 in lib/store-migrations.ts: one feedback flag, the two
offers).
The price cache, charades.prices.v1, is display only. It is written directly to MMKV,
outside Zustand persist, so a cold start paints prices on the first frame instead of
waiting on the network. RevenueCat persists CustomerInfo but not resolved store products,
and on Android the first getOfferings() also waits for a Play Billing connection. 30-day
TTL, replaced by every successful fetch, and never consulted by a purchase, which always
uses the live offering.
completedGames: see round-end-prompts.