docs(02-01): complete foundations plan

- 02-01-foundations-SUMMARY.md authored with frontmatter dependency
  graph, key-files manifest, decisions log, patterns established,
  test-count breakdown (72 new tests), TICK_MS=200 (no drift), and
  ESLint sim-purity rule landed (defended-option clause did not trigger)
- STATE.md: Phase 2 progress 1/5 plans (Wave 0 complete);
  velocity table updated with Plan 02-01 ~12min entry; decisions log
  cites BLOCKER 3 split, V1Payload extension, ESLint rule
- ROADMAP.md: Phase 2 row updated to 1/5; 02-01 plan marked [x] with
  duration + summary backlink
- REQUIREMENTS.md: CORE-02, CORE-03, CORE-11, UX-10, UX-11 marked
  complete with annotations; traceability table updated

Plan execution metrics:
- 3 atomic commits (58db532, fe99058, 2a8d354)
- 72 new tests across 9 test files (cushion above plan estimate of 54)
- Total test count: 128/128 green
- npm run ci exits 0
- Duration: ~12 min (sequential mode)
This commit is contained in:
2026-05-09 09:26:37 -04:00
parent 2a8d354b58
commit 38535bac73
4 changed files with 238 additions and 30 deletions
+11 -10
View File
@@ -11,8 +11,8 @@ 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. -->
- [ ] **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.
- [ ] **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*.
- [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-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. -->
@@ -20,7 +20,7 @@ Requirements for initial release. Each maps to roadmap phases. All are user-cent
- [x] **CORE-08**: Game keeps the last 3 pre-migration save snapshots and offers the player a "restore previous save" option in settings. <!-- Plan 01-03: RETAIN=3 enforced; 5-then-3 invariant test green. Settings UI surface is Phase 2. -->
- [x] **CORE-09**: Player can export their save as a Base64 text blob via Settings → Export and import it back into the same or a fresh browser via Settings → Import. <!-- Plan 01-03: exportToBase64/importFromBase64 + 50MB DoS cap; 3 round-trip tests green. Settings UI surface is Phase 2. -->
- [x] **CORE-10**: Game's simulation core (`src/sim/`) imports nothing from `src/render/` or `src/ui/` — enforced by ESLint boundary rules in CI. <!-- Plan 01-02: ESLint 9 flat config + boundaries/element-types rule + programmatic Vitest proof; lint exits 0. -->
- [ ] **CORE-11**: Simulation refuses negative time deltas (system-clock cheat defense) and caps any single offline progression at 24 hours, regardless of wall-clock claim.
- [x] **CORE-11**: Simulation refuses negative time deltas (system-clock cheat defense) and caps any single offline progression at 24 hours, regardless of wall-clock claim. <!-- Plan 02-01: drainTicks(state, accumulatorMs<0) returns the original state with ticksApplied=0; computeOfflineCatchup reports cappedMs=0 for negative deltas; 24h clamp shared with CORE-03; 5 catchup tests + 4 tick tests green. -->
### GARDEN — Planting, Growing, Harvesting
@@ -94,8 +94,9 @@ 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).
- [ ] **UX-10**: Game saves state on `visibilitychange` to hidden, on `beforeunload`, and on Season transitions; behavior is identical between "tab backgrounded" and "tab closed."
- [ ] **UX-11**: Numbers display in human-readable formats (1.2K, 4.5M, 8.9B, scientific notation past notation thresholds).
- [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-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).
- [x] **UX-13**: No daily login bonuses, no streaks, no limited-time content, no nag notifications, no loss-aversion copy — anti-FOMO doctrine is enforced in every UX review. <!-- Plan 01-06: .planning/anti-fomo-doctrine.md (17 banned mechanics, review checklist) authored and doc-lint tested; enforced by review per CONTEXT D-07. -->
@@ -191,8 +192,8 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
| Requirement | Phase | Status |
|-------------|-------|--------|
| 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) | Pending |
| CORE-03 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
| 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-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) |
@@ -200,7 +201,7 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
| CORE-08 | Phase 1 — Foundations & Doctrine | Complete (last-3 snapshot retention; Settings UI surface is Phase 2) |
| CORE-09 | Phase 1 — Foundations & Doctrine | Complete (Base64 export/import + 50MB DoS cap; Settings UI surface is Phase 2) |
| CORE-10 | Phase 1 — Foundations & Doctrine | Complete (ESLint boundary rule + Vitest proof) |
| CORE-11 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
| CORE-11 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-01; drainTicks refuses negative deltas + computeOfflineCatchup clamps to 0; ESLint sim-purity rule mechanically enforces D-33) |
| GARD-01 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
| GARD-02 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
| GARD-03 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
@@ -256,8 +257,8 @@ 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) | Pending |
| UX-11 | Phase 2 — Season 1 Vertical Slice (Soil) | 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-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) |
| PIPE-01 | Phase 1 — Foundations & Doctrine | Complete (Vite-native loader + Zod schemas; build fails on schema violation) |