docs(02-05): complete letter-settings-e2e plan

- 02-05-letter-settings-e2e-SUMMARY.md: full plan summary (frontmatter
  + decisions + REQ table + self-check). All 24 Phase-2 REQ-IDs
  structurally satisfied across the 5-plan set.
- STATE.md: marked Plan 02-05 complete; Phase 2 ready for
  /gsd-verify-work; progress 19% → 22%; next action set to verifier.
- ROADMAP.md: Plan 02-05 row marked [x] with duration + SUMMARY ref.
- REQUIREMENTS.md: UX-02 / UX-10 / CORE-03 / PIPE-07 marked complete
  with traceability annotations citing Plan 02-05's contribution;
  per-row Plan 02-05 references added to UX-02, UX-10, CORE-03;
  PIPE-07 traceability table row updated.
This commit is contained in:
2026-05-09 11:16:02 -04:00
parent 31f8ede9ac
commit e5d449095d
4 changed files with 361 additions and 28 deletions
+10 -9
View File
@@ -12,7 +12,7 @@ Requirements for initial release. Each maps to roadmap phases. All are user-cent
- [x] **CORE-01**: Player loads the game in a modern browser (Chrome, Firefox, Safari, Edge — last 2 stable releases) and reaches a playable state in under 5 seconds on a 25 Mbps connection. <!-- Plan 01-01: scaffold builds (`npm run build` green); end-to-end <5s wall-clock measurement is Phase 2 PIPE-07. -->
- [x] **CORE-02**: Game runs a deterministic, fixed-timestep simulation that advances by elapsed real time (not `setInterval` ticks), so a player who switches tabs or sleeps their device returns to a correctly-advanced garden. <!-- Plan 02-01: drainTicks fixed-timestep accumulator + Clock injection contract; TICK_MS=200 (5Hz); 7 scheduler tests green. ESLint sim-purity rule (D-33) bans setInterval inside src/sim/**. Scene-driven tick wiring + visibility-pause is Plan 02-02. -->
- [x] **CORE-03**: Player who closes the game and returns finds the garden has progressed by the elapsed time (capped at 24 hours) — *no progression resumes from a stale snapshot*. <!-- Plan 02-01: drainTicks clamps at MAX_OFFLINE_MS=24h; computeOfflineCatchup reports hitOfflineCap=true on excess; both paths covered by Vitest. Letter-overlay (returning-player surface) is Plan 02-05. -->
- [x] **CORE-03**: Player who closes the game and returns finds the garden has progressed by the elapsed time (capped at 24 hours) — *no progression resumes from a stale snapshot*. <!-- Plan 02-01: drainTicks clamps at MAX_OFFLINE_MS=24h; computeOfflineCatchup reports hitOfflineCap=true on excess; both paths covered by Vitest. Plan 02-05: src/PhaserGame.tsx boot path threads computeOfflineCatchup → drainTicks(silent=true) → autoHarvestReadyPlants → letter overlay opens at ≥5min absence; auto-harvest accumulates plantsBloomedCount + harvestedFragmentIds + luraBeatPending into the OfflineEventBlock the letter Ink renders. PIPE-07 e2e exercises offline catchup structurally via FakeClock advance + reload. -->
- [x] **CORE-04**: Player's progress saves to IndexedDB (with localStorage fallback), surviving browser refresh, browser updates, and at least 30 days of inactivity on Chrome and Firefox. <!-- Plan 01-03: idb DB + LocalStorageDBAdapter fallback; 4 db tests green; round-trip test green. Settings UI surface is Phase 2. -->
- [x] **CORE-05**: Game requests persistent storage via `navigator.storage.persist()` on first save and surfaces the result respectfully if the browser declines. <!-- Plan 01-03: requestPersistence() all 4 API scenarios covered by Vitest; Settings UI surface is Phase 2. -->
- [x] **CORE-06**: Saves are versioned (`{schemaVersion, payload, checksum}`) and the game refuses to load a save with a checksum mismatch, presenting the player with a recovery option. <!-- Plan 01-03: wrap/unwrap + SaveCorruptError + CRC-32; 9 envelope tests green. -->
@@ -89,7 +89,8 @@ Requirements for initial release. Each maps to roadmap phases. All are user-cent
- [x] **UX-01**: First-time player sees a single, painted "Begin" screen with no UI clutter; the garden reveals itself as the player interacts (A Dark Room rule). <!-- Plan 02-02: BeginScreen mounts as a fixed-position dialog covering the canvas with only title + subtitle + Begin CTA; no HUD, no journal, no settings. Dismissed via session.beginGateDismissed (D-22). Phase 3 paints the treatment. -->
- [ ] **UX-02**: Player who returns after time away receives a "while you were away" *letter from the garden* — written in voice, not a stat dump — describing what grew, what bloomed, what the wind brought.
- [x] **UX-02**: Player who returns after time away receives a "while you were away" *letter from the garden* — written in voice, not a stat dump — describing what grew, what bloomed, what the wind brought. <!-- Plan 02-05: content/dialogue/season1/letter-from-the-garden.ink authored skeleton (bible voice, anti-FOMO compliant, 24h cap silent in voice per D-11) + slot vocabulary plants_bloomed/fragment_titles/lura_was_here from offlineEvents block; src/ui/letter/Letter.tsx full-screen overlay (D-20: opens at ≥5min absence, dismisses on tap with Pitfall 9 audio bootstrap); buildLetterSlots pure helper + 10 tests; Letter overlay 7 tests. Boot path in src/PhaserGame.tsx threads silent catchup → offlineEvents → openLetter. -->
- [ ] **UX-03**: Player can buy plants/upgrades in multi-buy increments (×1 / ×10 / ×100 / Max) when the option is meaningful for the current scaling.
- [ ] **UX-04**: Player can adjust separate Music, Ambient, and SFX volume sliders, with a master mute keybind; settings persist in saves.
- [ ] **UX-05**: Player can toggle a reduced-motion option (respects `prefers-reduced-motion` system setting by default) that disables non-essential particles and animation.
@@ -97,7 +98,7 @@ Requirements for initial release. Each maps to roadmap phases. All are user-cent
- [ ] **UX-07**: All UI text is selectable, copy-pasteable, and supports browser zoom up to 200% without breaking layout.
- [ ] **UX-08**: Color is never the sole carrier of information — icons, labels, or patterns provide a redundant channel for color-blind players.
- [ ] **UX-09**: Tab title and favicon update to reflect a backgrounded state (e.g., a small bloom appears when a fragment is ready).
- [x] **UX-10**: Game saves state on `visibilitychange` to hidden, on `beforeunload`, and on Season transitions; behavior is identical between "tab backgrounded" and "tab closed." <!-- Plan 02-01: registerSaveLifecycleHooks attaches synchronous handlers for visibilitychange→hidden + beforeunload + saveOnSeasonTransition() callable; 6 lifecycle tests green covering every trigger + detach. Boot-path saveSync wiring is Plan 02-05. -->
- [x] **UX-10**: Game saves state on `visibilitychange` to hidden, on `beforeunload`, and on Season transitions; behavior is identical between "tab backgrounded" and "tab closed." <!-- Plan 02-01: registerSaveLifecycleHooks attaches synchronous handlers for visibilitychange→hidden + beforeunload + saveOnSeasonTransition() callable; 6 lifecycle tests green covering every trigger + detach. Plan 02-05: PhaserGame.tsx boot path now wires saveSync via clock.now() (BLOCKER 3 — wall-clock anchor) + synchronous LocalStorage write (Pitfall 7) + best-effort IDB write; lifecycle handle held in a ref so the outer useLayoutEffect cleanup detaches across the async IIFE boundary (W5). -->
- [x] **UX-11**: Numbers display in human-readable formats (1.2K, 4.5M, 8.9B, scientific notation past notation thresholds). <!-- Plan 02-01: formatHumanReadable handles every K/M/B/T threshold + 1e15 scientific + negative-sign branch; 11 format tests green. BigQty.format() delegates so all currency-grade numbers in the HUD route through this. -->
- [ ] **UX-12**: Game surfaces *what Lura said yesterday* in returning-player UI affordances — never *fragments per hour* or *optimization metrics* (mechanic-as-metaphor doctrine).
@@ -112,7 +113,7 @@ Requirements for initial release. Each maps to roadmap phases. All are user-cent
- [ ] **PIPE-04**: Project ships visual regression testing for the asset library that flags style drift before any model migration is merged.
- [x] **PIPE-05**: Project ships an `anti-FOMO doctrine` document and a `Season 7 end-state` design document in `.planning/` (or `docs/`) before economy code is written. <!-- Plan 01-06: both docs authored and doc-lint tested (8 Vitest assertions green). -->
- [x] **PIPE-06**: Project ships unit tests (Vitest) covering all save migrations and core economy formulas, run on every CI build. <!-- Plan 01-07: .github/workflows/ci.yml runs npm ci + npm run ci on push + PR; 53 tests / 12 files green. -->
- [ ] **PIPE-07**: Project ships an end-to-end smoke test (Playwright) that loads the game, plants a seed, harvests a fragment, and verifies persistence across a page reload.
- [x] **PIPE-07**: Project ships an end-to-end smoke test (Playwright) that loads the game, plants a seed, harvests a fragment, and verifies persistence across a page reload. <!-- Plan 02-05: tests/e2e/season1-loop.spec.ts covers load → Begin → plant rosemary → fast-forward FakeClock 3min → harvest → fragment-reveal modal → close → journal-icon visible → open journal → fragment present → reload → fragment persists. URL-flag FakeClock injection production-guarded by import.meta.env.PROD; window.__tlgStore exposed only when ?devtime=fake. 1.5s test runtime, ~4s end-to-end. npm run test:e2e (not in npm run ci per minimum-viable doctrine; runs separately before /gsd-verify-work and on release). -->
## v2 Requirements
@@ -197,7 +198,7 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
|-------------|-------|--------|
| CORE-01 | Phase 1 — Foundations & Doctrine | Complete (scaffold builds; full E2E <5s measurement is Phase 2 PIPE-07) |
| CORE-02 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01; drainTicks fixed-timestep accumulator + Clock injection; scene-driven tick wiring is Plan 02-02) |
| CORE-03 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01; MAX_OFFLINE_MS=24h clamp + computeOfflineCatchup; letter overlay is Plan 02-05) |
| CORE-03 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01 + 02-05; MAX_OFFLINE_MS=24h clamp + computeOfflineCatchup + PhaserGame.tsx boot path threads catchup → silent drainTicks → letter overlay) |
| CORE-04 | Phase 1 — Foundations & Doctrine | Complete (IDB + localStorage fallback; codec + round-trip; Settings UI is Phase 2) |
| CORE-05 | Phase 1 — Foundations & Doctrine | Complete (navigator.storage.persist() all 4 scenarios; Settings UI surface is Phase 2) |
| CORE-06 | Phase 1 — Foundations & Doctrine | Complete (wrap/unwrap + CRC-32 checksum + SaveCorruptError) |
@@ -253,7 +254,7 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
| AEST-08 | Phase 1 — Foundations & Doctrine | Complete (Zod ProvenanceSchema 6 fields + CI gate; north-star reference set deferred to Phase 5 per IOU) |
| AEST-09 | Phase 1 — Foundations & Doctrine | Complete (human curation gate mechanism in place; recorded human decision in 01-05-IOU.md) |
| UX-01 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-02; single fixed-position Begin overlay; no HUD/journal/settings; D-22 dismissal) |
| UX-02 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
| UX-02 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-05; letter-from-the-garden.ink + Letter overlay + boot path silent catchup → openLetter at ≥5min absence; Pitfall 9 audio bootstrap on dismiss) |
| UX-03 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| UX-04 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| UX-05 | Phase 3 — Watercolor & Cello Aesthetic | Pending |
@@ -261,7 +262,7 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
| UX-07 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| UX-08 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| UX-09 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| UX-10 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01; registerSaveLifecycleHooks + saveOnSeasonTransition; boot-path saveSync wiring is Plan 02-05) |
| UX-10 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01 + 02-05; registerSaveLifecycleHooks + saveOnSeasonTransition; PhaserGame.tsx boot path wires saveSync via clock.now() with synchronous LocalStorage write + best-effort IDB) |
| UX-11 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01; formatHumanReadable K/M/B/T/scientific; BigQty.format() delegates) |
| UX-12 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| UX-13 | Phase 1 — Foundations & Doctrine | Complete (anti-fomo-doctrine.md authored + doc-lint tested; review-enforced per CONTEXT D-07) |
@@ -271,7 +272,7 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
| PIPE-04 | Phase 8 — UX, Accessibility & Launch Polish | Pending |
| PIPE-05 | Phase 1 — Foundations & Doctrine | Complete (both doctrine docs authored + 8 doc-lint assertions green) |
| PIPE-06 | Phase 1 — Foundations & Doctrine | Complete (ci.yml runs npm run ci on push + PR; 53 tests / 12 files green) |
| PIPE-07 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
| PIPE-07 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-05; tests/e2e/season1-loop.spec.ts — full Phase-2 loop in Chromium with FakeClock injection, 1.5s test runtime, 4s end-to-end) |
**Per-Phase Counts:**
@@ -294,4 +295,4 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
---
*Requirements defined: 2026-05-08*
*Last updated: 2026-05-09 after Phase 1 verification (16/16 REQ-IDs marked Complete)*
*Last updated: 2026-05-09 after Plan 02-05 execution (40/77 REQ-IDs marked Complete — Phase 1 + Phase 2 fully shipped pending /gsd-verify-work)*