Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ddaabcdc1 | |||
| a641056364 | |||
| d065922cad | |||
| e5c55b0aae | |||
| a9f190ed27 | |||
| 953784ae93 | |||
| f6bef061c3 | |||
| f7428da299 | |||
| 63d2d8d5f7 | |||
| 5bc98ba4ac | |||
| 01e02dcdb8 | |||
| c4589a56b4 | |||
| 350e976fed | |||
| 69964ba17f |
@@ -55,7 +55,13 @@ Plans:
|
|||||||
3. Player can compost an immature plant and receive a tonal beat acknowledging the choice to let go; the deterministic fragment selector never duplicates a fragment within a playthrough until the pool is exhausted, respects authored Season/story-state gating, and Lura appears at the garden gate with text-message-cadence dialogue authored in Ink and compiled to JSON.
|
3. Player can compost an immature plant and receive a tonal beat acknowledging the choice to let go; the deterministic fragment selector never duplicates a fragment within a playthrough until the pool is exhausted, respects authored Season/story-state gating, and Lura appears at the garden gate with text-message-cadence dialogue authored in Ink and compiled to JSON.
|
||||||
4. Player who closes the tab and returns up to 24 hours later finds the garden has progressed by elapsed real time (not `setInterval` ticks), with the simulation refusing negative deltas and capping any single offline catch-up at 24 hours; the return screen is a *letter from the garden* (not a stat dump) describing what bloomed and what Lura said, and saves fire correctly on `visibilitychange` to hidden, on `beforeunload`, and on Season transitions.
|
4. Player who closes the tab and returns up to 24 hours later finds the garden has progressed by elapsed real time (not `setInterval` ticks), with the simulation refusing negative deltas and capping any single offline catch-up at 24 hours; the return screen is a *letter from the garden* (not a stat dump) describing what bloomed and what Lura said, and saves fire correctly on `visibilitychange` to hidden, on `beforeunload`, and on Season transitions.
|
||||||
5. A Playwright e2e smoke test passes: it loads the game, dismisses the begin gate, plants a seed, fast-forwards growth, harvests a fragment, verifies the fragment text appears in the journal, refreshes the page, and verifies the harvested fragment persists. Story progression gates on tick count (not wall time), so manipulating the system clock cannot fast-forward through Lura's authored beats.
|
5. A Playwright e2e smoke test passes: it loads the game, dismisses the begin gate, plants a seed, fast-forwards growth, harvests a fragment, verifies the fragment text appears in the journal, refreshes the page, and verifies the harvested fragment persists. Story progression gates on tick count (not wall time), so manipulating the system clock cannot fast-forward through Lura's authored beats.
|
||||||
**Plans**: TBD
|
**Plans:** 5 plans
|
||||||
|
Plans:
|
||||||
|
- [ ] 02-01-foundations-PLAN.md — BigQty + Zustand 5 store + tick scheduler + V1Payload extension + save lifecycle hooks + Phaser EventBus singleton + ESLint sim-purity rule (Wave 0; foundations every other Phase-2 plan depends on)
|
||||||
|
- [ ] 02-02-begin-plant-grow-PLAN.md — sim/garden core (4×4 grid, 3 plant types, growth state machine, plantSeed) + render layer (Phaser primitives, ready-pulse, tile-coords) + BeginScreen + audio bootstrap + SeedPicker + UI strings (Wave 1; AEST-07, UX-01, GARD-01, GARD-02)
|
||||||
|
- [ ] 02-03-harvest-journal-fragments-PLAN.md — Season-1 ≥10 authored fragments + sim/memory selector (deterministic, gated, no-dup, exhaustion) + harvest + compost + Memory Journal + FragmentRevealModal + JournalIcon + PIPE-02 structural verification (Wave 1; GARD-03, GARD-04, MEMR-01..06, PIPE-02)
|
||||||
|
- [ ] 02-04-lura-gate-beats-PLAN.md — inklecate compile pipeline + 4 authored .ink files (3 Lura beats + compost acknowledgements) + sim/narrative tick-count gate (1st/4th/8th harvest) + LuraDialogue overlay + InkRenderer drip + Phaser gate visual indicator (Wave 2; STRY-01, STRY-06, STRY-07 vacuous, STRY-10)
|
||||||
|
- [ ] 02-05-letter-settings-e2e-PLAN.md — sim/offline + auto-harvest + letter Ink + Letter overlay + Settings (Export/Import/Restore) + persistence-toast + boot-path save lifecycle wiring + URL-flag FakeClock injection + Playwright PIPE-07 e2e (Wave 2; UX-02, UX-10, CORE-03, CORE-11, PIPE-07)
|
||||||
**UI hint**: yes
|
**UI hint**: yes
|
||||||
|
|
||||||
### Phase 3: Watercolor & Cello Aesthetic
|
### Phase 3: Watercolor & Cello Aesthetic
|
||||||
|
|||||||
+10
-10
@@ -2,9 +2,9 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: complete
|
status: ready_to_execute
|
||||||
stopped_at: "Phase 1 complete. All 16 REQ-IDs verified (CORE-01, CORE-04..CORE-10, PIPE-01, PIPE-03, PIPE-05, PIPE-06, AEST-08, AEST-09, STRY-09, UX-13). CI chain green: lint + 53 tests + validate-assets + build all exit 0. One known deferred item: 10-20 real north-star reference images (AEST-09 Task 2) recorded in 01-05-IOU.md — Phase 5 follow-up, does not block Phase 2. Next: /gsd-discuss-phase 2."
|
stopped_at: "Phase 2 planned. 5 PLAN.md files across 3 waves (Wave 0: 02-01 foundations [BigQty + Zustand store + tick scheduler + V1Payload extension]; Wave 1 parallel: 02-02 begin-plant-grow + 02-03 harvest-journal-fragments; Wave 2 parallel: 02-04 lura-gate-beats + 02-05 letter-settings-e2e). 24/24 REQ-IDs covered in plan frontmatter; 34/34 CONTEXT.md decisions cited across plan must_haves. RESEARCH.md, PATTERNS.md, VALIDATION.md (nyquist_compliant: true) all in place. Plan-checker iterations: 13 issues → 3 issues → 0 issues (BLOCKER 3 lastTickAt-vs-tickCount split was the cross-plan defect; final fix introduced src/save/payload.ts as a shared two-arg helper module). Next: /gsd-execute-phase 2 (Wave 0 must land before Waves 1+2 can start)."
|
||||||
last_updated: "2026-05-09T00:20:00.000Z"
|
last_updated: "2026-05-09T01:30:00.000Z"
|
||||||
last_activity: 2026-05-09
|
last_activity: 2026-05-09
|
||||||
progress:
|
progress:
|
||||||
total_phases: 8
|
total_phases: 8
|
||||||
@@ -21,14 +21,14 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-05-08)
|
See: .planning/PROJECT.md (updated 2026-05-08)
|
||||||
|
|
||||||
**Core value:** Every idle mechanic must function as a metaphor that the player absorbs without being told. When economy and meaning conflict, meaning wins.
|
**Core value:** Every idle mechanic must function as a metaphor that the player absorbs without being told. When economy and meaning conflict, meaning wins.
|
||||||
**Current focus:** Phase 02 — Season 1 Vertical Slice (Soil) — READY TO BEGIN
|
**Current focus:** Phase 02 — Season 1 Vertical Slice (Soil) — 5 plans ready; ready for `/gsd-execute-phase 2`
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 01 (foundations-and-doctrine) — COMPLETE (verified 2026-05-09)
|
Phase: 02 (season-1-vertical-slice-soil) — planned, ready to execute
|
||||||
Plan: 7 of 7 complete
|
Plans: 5 of 5 created (3 waves)
|
||||||
Status: All 16 Phase-1 REQ-IDs verified; CI green; ready for Phase 2
|
Status: All 24 REQ-IDs + 34 CONTEXT.md decisions covered. Plan-checker PASSED after 3 revision iterations. Ready for `/gsd-execute-phase 2`.
|
||||||
Last activity: 2026-05-09 -- Phase 1 verification complete
|
Last activity: 2026-05-09 -- Phase 2 plan-phase complete
|
||||||
|
|
||||||
Progress: [█░░░░░░░░░] 12%
|
Progress: [█░░░░░░░░░] 12%
|
||||||
|
|
||||||
@@ -117,5 +117,5 @@ Items acknowledged and carried forward:
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-05-09
|
Last session: 2026-05-09
|
||||||
Stopped at: Phase 1 verification complete — VERIFICATION.md written, REQUIREMENTS.md updated (16 REQ-IDs marked Complete), STATE.md updated to `status: complete`. All gates green (lint, 53 tests, validate:assets, build, CI chain).
|
Stopped at: Phase 2 planning complete — 5 PLAN.md files written across 3 waves; plan-checker PASSED after 3 revision iterations (13 issues → 3 → 0); all 24 REQ-IDs and 34 D-XX decisions covered.
|
||||||
Next action: `/gsd-discuss-phase 2` to begin Season 1 Vertical Slice (Soil)
|
Next action: `/gsd-execute-phase 2` to execute the Season 1 Vertical Slice (Wave 0 first; Waves 1+2 can run in parallel within their wave)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1299
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,216 @@
|
|||||||
|
# Phase 2: Season 1 Vertical Slice (Soil) - Context
|
||||||
|
|
||||||
|
**Gathered:** 2026-05-09
|
||||||
|
**Status:** Ready for planning
|
||||||
|
|
||||||
|
<domain>
|
||||||
|
## Phase Boundary
|
||||||
|
|
||||||
|
Ship the complete Season 1 (Soil) vertical slice end-to-end on real authored content, with no aesthetic polish required. Player launches → presses **Begin** (gesture-gate calls `AudioContext.resume()`, AEST-07) → places a seed in an empty tile of a 4×4 garden → watches it grow (state survives refresh) → harvests one Season-1 fragment → reads it in a Memory Journal → meets Lura at the gate via Ink-authored dialogue → closes the tab → returns to a *letter from the garden* describing what bloomed → the Playwright e2e smoke proves the whole loop. The simulation advances by elapsed real time (capped at 24h, refusing negative deltas), saves fire on `visibilitychange`/`beforeunload`/Season transitions, and story progression gates on tick count (not wall time).
|
||||||
|
|
||||||
|
Phase 2's first commits land the foundations Phase 1 deliberately deferred: the **`BigQty` wrapper around `break_eternity.js`** (per CLAUDE.md "from day one of feature code"), the **Zustand 5 store** wiring scenes ↔ React UI, and the **tick scheduler / monotonic clock** (the only owner of wall-clock access; sim modules stay pure).
|
||||||
|
|
||||||
|
**Out of scope for Phase 2 (deferred to later phases):**
|
||||||
|
- Watercolor post-process, painted plants, solo cello, ambient buses (Phase 3)
|
||||||
|
- Season transitions, die-off, Roothold prestige, cross-pollination (Phase 4)
|
||||||
|
- Place-memory vignettes, Memory Storms, the Nameless Man's full arc (Phase 5)
|
||||||
|
- The Below, ecosystem planting, the Loom, the Archivist (Phase 6)
|
||||||
|
- Final binary choice + credits/coda rest state (Phase 7)
|
||||||
|
- Audio sliders (UX-04), keyboard nav (UX-06), browser-zoom guarantees (UX-07), color-redundant icons (UX-08), tab-title bloom (UX-09), Lura-not-numbers UX (UX-12) (Phase 8)
|
||||||
|
- Visual regression for the asset library (PIPE-04, Phase 8)
|
||||||
|
|
||||||
|
**Phase 2 owns 24 REQ-IDs:** CORE-02, CORE-03, CORE-11, GARD-01, GARD-02, GARD-03, GARD-04, MEMR-01, MEMR-02, MEMR-03, MEMR-04, MEMR-05, MEMR-06, STRY-01, STRY-06, STRY-07 (vacuous in S1), STRY-10, AEST-07, UX-01, UX-02, UX-10, UX-11, PIPE-02, PIPE-07.
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
<decisions>
|
||||||
|
## Implementation Decisions
|
||||||
|
|
||||||
|
### Garden Geometry & Input
|
||||||
|
- **D-01:** Garden is a **4×4 fixed grid (16 tiles)**. Intimate walled-garden feel; matches cozy/contemplative tone and Phase 2's minimum-viable bias. Later Seasons add new surfaces (the Below, etc.) rather than enlarging the grid.
|
||||||
|
- **D-02:** Seed placement is **click-empty-tile → inline seed picker** (small popover anchored to the clicked tile, listing currently-unlocked plant types; single tap commits). No persistent seed sidebar — honors UX-01 "no UI clutter".
|
||||||
|
- **D-03:** **2–3 plant types** ship in Season 1 — enough that the player exercises real choice and different plants gate different fragments via MEMR-06. Each plant has its own growth duration and fragment pool.
|
||||||
|
- **D-04:** **Infinite seed supply from start** — anti-FOMO. The meaningful constraint is *time* (growth duration, tile count), not seed inventory. Simplest sim/store shape; cleanest cozy framing.
|
||||||
|
- **D-05:** **First plant available from start; remaining 1–2 unlock by fragment-count thresholds** harvested. Drip-feed of progression without ceremony. Specific thresholds are Claude's discretion within reason.
|
||||||
|
- **D-06:** Empty tile look in Phase 2 = **faint outlined tile + subtle hover state** (Phaser primitive draw, no asset work). Phase 3 paints the watercolor treatment.
|
||||||
|
- **D-07:** Post-harvest tile **returns immediately to empty** with a brief acknowledgement beat (small text snippet, gentle particle, or pause beat — Claude's discretion on form). No "spent" cooldown state in the sim or save schema.
|
||||||
|
|
||||||
|
### Time Density (Growth + Offline)
|
||||||
|
- **D-08:** First-plant active-play growth = **~2–5 minutes** (sprout → ready). Cozy but watchable; lets a playtester complete the full loop in ~10 minutes while still feeling idle. The 24h offline cap is meaningful, not just theoretical.
|
||||||
|
- **D-09:** **Per-plant durations vary** (short / medium / longer) within the ~2–5min band. Lets the player make real time-vs-yield tradeoffs and gives each plant a tonal identity. Specific durations per plant are Claude's discretion; document chosen values in PLAN.md.
|
||||||
|
- **D-10:** **Auto-harvest during offline; manual in active play.** While the player is away, plants that ripen are auto-harvested and queued into the offline event log; the *letter* narrates them. In active play, the player still chooses when to harvest. Cleanest idle-game shape and gives the letter content to describe.
|
||||||
|
- **D-11:** **24h offline cap is surfaced silently in the letter's voice** — no numeric "you were gone for 28 hours" copy. The simulation hard-caps the elapsed delta at 24h (CORE-03 + CORE-11); the letter may lightly acknowledge a long absence in voice, but never shows the cap as a system message.
|
||||||
|
|
||||||
|
### Lura's Season 1 Arc
|
||||||
|
- **D-12:** Lura is present as **discrete visits at the gate** — not a persistent chat thread. Matches the bible's framing; each visit is its own Ink scene; bounded content target for Phase 2.
|
||||||
|
- **D-13:** **3 beats in Season 1: arrival · mid · farewell.** Tight prologue arc; small authoring surface; load-bearing for tone.
|
||||||
|
- **D-14:** Beats are **gated by fragment-count thresholds** — beat 1 fires after the **1st** harvest; mid-beat after the **4th**; farewell after the **8th**. Counts come from sim ticks, not wall time, so STRY-10 holds (system-clock manipulation cannot fast-forward through beats). Specific thresholds may shift slightly during playtest but the model — fragment-count thresholds — is locked.
|
||||||
|
- **D-15:** Beat-fire UX = **subtle gate indicator + player-initiated visit.** When a beat unlocks, a soft cue at the gate signals it (glow, mark, or small text); the player walks over (clicks the gate) when they choose. The conversation opens as a **React DOM dialogue overlay** (DOM, not canvas — supports MEMR-05-style selectable text from day one). Honors A Dark Room rule.
|
||||||
|
- **D-16:** All Lura dialogue is authored in **Ink (`.ink`) under `/content/dialogue/`**, compiled to JSON via `inklecate` (already in devDependencies), runtime-loaded via `inkjs` (already in dependencies). Per STRY-06 + ROADMAP.md.
|
||||||
|
|
||||||
|
### Letter-from-the-Garden (UX-02)
|
||||||
|
- **D-17:** Letter is composed from an **authored skeleton + templated insertions**. Hand-authored Ink passages in voice with named variable slots (e.g., `{plants_bloomed}`, `{fragment_titles}`, `{lura_was_here}`); specifics flow in from the offline event log. Best balance of voice control (Lura-anchor tone is preserved by author) and reactivity (each return reads true to what happened).
|
||||||
|
- **D-18:** Letter authoring lives in **Ink (`.ink` files in `/content/dialogue/`)** — same authoring layer as Lura's beats. Single narrative-rendering path for Phase 2; reuses STRY-06 stack; no second loader path.
|
||||||
|
- **D-19:** Save schema gains a small **`offlineEvents`** block: per-plant counts of plants bloomed, list of auto-harvested fragment IDs, and a flag for any newly-unlocked Lura beat queued for first-visit. Compact and bounded; sufficient for the slot vocabulary; cleanly fits inside the existing `V1Payload` shape (see `src/save/migrations.ts`). Phase 2 must update `V1Payload` to include this block — it's a Phase-2 schema *extension*, not a `migrate_v1_to_v2`, because Phase 1's v1 has not shipped any production saves yet.
|
||||||
|
- **D-20:** Letter triggers on return when **absence ≥ 5 minutes**. Below 5 minutes, the player simply resumes (no letter). At/above the threshold, a **full-screen React DOM overlay** delivers the letter; **one tap dismisses to the live garden**. Threshold avoids letter-spam during active tab-flicking; full-screen treatment honors the tonal weight.
|
||||||
|
|
||||||
|
### Begin Screen (AEST-07 + UX-01)
|
||||||
|
- **D-21:** **Tasteful placeholder; Phase 3 paints.** Phase 2 ships a clean, restrained Begin screen — typographic title + a single "Begin" affordance, calls `AudioContext.resume()` on tap. No painted canvas illustration. Phase 3 swaps in the watercolor gesture-gate without touching the gating logic.
|
||||||
|
- **D-22:** **Begin screen shows on first run only.** Subsequent loads skip directly to the live garden; `AudioContext` enables on the first interaction (any tile click or gate click counts as a user gesture). "First run" is determined by save existence (no save → first run; save present → returning player). Acknowledged tradeoff: returning players have a brief silent moment until their first interaction; deemed acceptable for cozy-pacing.
|
||||||
|
|
||||||
|
### Memory Journal (MEMR-04, MEMR-05)
|
||||||
|
- **D-23:** Journal affordance **reveals after the player's first harvest**, then is persistent. Pre-harvest, no journal icon at all. Most A-Dark-Room-consistent; the UI grows as the player progresses.
|
||||||
|
- **D-24:** Journal layout = **full-screen modal overlay** with fragments grouped by Season; a back affordance returns to the live garden. DOM-rendered text per MEMR-05 (selectable, copy-pasteable).
|
||||||
|
- **D-25:** Newly harvested fragments (in active play) **surface immediately in a full-text reveal modal**; dismissing files them into the journal under their Season. Off-line auto-harvested fragments are surfaced via the *letter* (D-17 .. D-20) and re-readable in the journal afterwards. Creates a memorable beat-per-harvest in active play; preserves the cozy/quiet feel of the offline return.
|
||||||
|
|
||||||
|
### Visual Placeholders (Phase 2 only)
|
||||||
|
- **D-26:** Plants render as **simple Phaser-primitive shapes per growth stage, tinted by plant type**. Sprout = small dot, mature = stem, ready = bloom shape; tint differentiates plant types. No PNG asset work in Phase 2; the architectural firewall stays clean (no asset deps in `src/sim/`). Phase 3 swaps in painted sprites.
|
||||||
|
- **D-27:** Ready-state cue = **subtle glow / pulse on ready tiles** (Phaser shader pulse or alpha cycle). Reads at a glance without text; works regardless of plant type; Phase 3 paints over with a warmer light treatment.
|
||||||
|
|
||||||
|
### Phase 2 Settings UI Scope
|
||||||
|
- **D-28:** Settings menu in Phase 2 ships **save-management surfaces only** — Export to Base64 (CORE-09 UI), Import from Base64 (CORE-09 UI), Restore previous snapshot (CORE-08 UI). Persistence-result toast (CORE-05 UI) folds in. **Audio sliders + keyboard nav + browser zoom + color-redundant icons stay in Phase 8** (UX-04, UX-06, UX-07, UX-08).
|
||||||
|
- **D-29:** Settings access = **small icon in a corner of the main view + keyboard shortcut**. Persistent (returning players need to find Export/Import for save recovery); restrained enough not to clutter the cozy surface. Same pattern as the Memory Journal affordance.
|
||||||
|
- **D-30:** `navigator.storage.persist()` outcome surfaced as a **one-time soft toast in voice on first save if denied; nothing if granted** (e.g., *"the garden may forget, if your browser asks it to"*). Honors UX-01 + cozy tone; respects CORE-05's "surfaces the result respectfully if the browser declines."
|
||||||
|
|
||||||
|
### Foundations That Must Land in Phase 2 (per CLAUDE.md)
|
||||||
|
- **D-31:** **`BigQty` wrapper around `break_eternity.js`** is Phase 2's first task. Lands in `src/sim/numbers/` (or similar firewall-respecting location). All economy values from this point forward go through `BigQty`. Even if Season 1's actual scaling never demands `break_eternity`, the wrapper is in place day-one of feature code per CLAUDE.md.
|
||||||
|
- **D-32:** **Zustand 5 store** is the bridge between the Phaser scene and React UI surfaces (Begin screen, Memory Journal, Settings, Letter, Lura dialogue). Sim writes to the store; React reads from it. Sim never imports the store directly — Phase 1's ESLint boundaries (CORE-10) enforce this. Exact slice shape is Claude's discretion.
|
||||||
|
- **D-33:** **Tick scheduler / monotonic clock** is the *only* owner of wall-clock access. Sim modules in `src/sim/` stay pure (no `Date.now`, no `setInterval`); the scheduler injects `currentTime` into sim updates. Tick rate is Claude's discretion (likely 4–10Hz for sim updates, decoupled from `requestAnimationFrame`-driven render). Negative deltas are refused at the scheduler boundary (CORE-11); single offline catch-up clamps to 24h (CORE-03 + CORE-11).
|
||||||
|
- **D-34:** **Save extension for Phase 2** updates `V1Payload` (in `src/save/migrations.ts`) to include the Phase-2-needed fields: garden tiles with plant state, plants array with growth-state + plantedAt-tick, harvested fragment IDs (already declared), `lastTickAt` (already declared), Lura-beat progress flags, `offlineEvents` block (D-19), settings (already declared). This is a Phase-2-scope schema *extension* (not a v1→v2 migration) because Phase 1's v1 envelope has shipped no production saves; the synthetic v0→v1 demo migration in `migrations[1]` continues to work.
|
||||||
|
|
||||||
|
### Claude's Discretion
|
||||||
|
- Specific growth-duration values per plant type within the 2–5min band (D-08 / D-09).
|
||||||
|
- Exact fragment-count threshold values for plant-type unlocks (D-05) and Lura beats — the model is locked (1st/4th/8th) but Claude may adjust by ±1–2 during playtest.
|
||||||
|
- Form of the post-harvest acknowledgement beat (text snippet, particle, pause — D-07).
|
||||||
|
- Form of the gate indicator when Lura's beat unlocks (D-15) — soft glow, mark, or small text.
|
||||||
|
- Tick rate / sim cadence (likely 4–10Hz; not 60Hz — sim should be cheap).
|
||||||
|
- Internal shape of the Zustand store slices.
|
||||||
|
- Internal shape of the scene/state machine inside Phaser (Boot → Preloader → Garden, or simpler).
|
||||||
|
- Specific copy of the tasteful Begin screen, the persistence-denied toast, and the post-harvest acknowledgement (all must match the bible voice; user reviews).
|
||||||
|
- Choice of e2e test fast-forward mechanism (hidden dev hotkey vs URL flag vs sim-clock injection — Phase 2 needs *some* way for Playwright to fast-forward growth in PIPE-07).
|
||||||
|
- Specific copy of the Memory Journal "no fragments yet" empty state (if shown pre-first-harvest in any flow).
|
||||||
|
- Whether the offline letter's slot vocabulary is finalized in this phase or expanded incrementally (Lura's variable can be the simplest first slot; more added if needed).
|
||||||
|
|
||||||
|
</decisions>
|
||||||
|
|
||||||
|
<canonical_refs>
|
||||||
|
## Canonical References
|
||||||
|
|
||||||
|
**Downstream agents MUST read these before planning or implementing.**
|
||||||
|
|
||||||
|
### Project-Level Source of Truth
|
||||||
|
- `.planning/PROJECT.md` — Story bible synthesis, core value ("every idle mechanic must function as a metaphor"), hard thematic constraints, Out of Scope, Key Decisions table.
|
||||||
|
- `.planning/REQUIREMENTS.md` — 77 v1 requirements with REQ-IDs. Phase 2 owns 24 (see Phase Boundary above for the complete list).
|
||||||
|
- `.planning/ROADMAP.md` §"Phase 2: Season 1 Vertical Slice (Soil)" — 5 success criteria. The plan must satisfy each.
|
||||||
|
- `.planning/STATE.md` — current position; Phase 1 verification table; carry-forward concerns.
|
||||||
|
- `CLAUDE.md` — stack lock, architectural firewall, banner concerns 1–10, hard thematic constraints, code style rules ("BigQty from day one of feature code", externalized strings, stable string IDs, no Date.now in sim).
|
||||||
|
|
||||||
|
### Phase 1 Outputs (load-bearing for Phase 2)
|
||||||
|
- `.planning/phases/01-foundations-and-doctrine/01-CONTEXT.md` — Phase 1 decisions (D-01..D-12) that constrain Phase 2 (save format locked, content pipeline locked, firewall locked, doctrine docs locked).
|
||||||
|
- `.planning/phases/01-foundations-and-doctrine/01-VERIFICATION.md` — Phase 1 PASS evidence; Phase 2 builds on every green REQ here.
|
||||||
|
- `.planning/anti-fomo-doctrine.md` — banned UX patterns; review checklist. **MUST be consulted at every UX decision in Phase 2.**
|
||||||
|
- `.planning/season-7-end-state.md` — the principle-level rest-state contract. Phase 2's growth-curve and Roothold-precursor decisions must not preclude the finite ceiling tied to authored content.
|
||||||
|
|
||||||
|
### Research Layer
|
||||||
|
- `.planning/research/SUMMARY.md` — stack at a glance, banner concerns, Phase 2 rationale (vertical slice that could plausibly ship as a free standalone prologue).
|
||||||
|
- `.planning/research/STACK.md` — stack rationale; especially the React-19-DOM-overlay vs Phaser-canvas split, Zustand 5 bridge, Howler.js, Ink/inkjs, idb + lz-string.
|
||||||
|
- `.planning/research/ARCHITECTURE.md` — three-layer firewall (sim → application → presentation); tick scheduler shape; save format `{schemaVersion, payload, checksum}`.
|
||||||
|
- `.planning/research/PITFALLS.md` — 14 critical pitfalls. Phase 2 directly hits #1 (story-ends-but-loop-doesn't — vertical-slice prologue must not foreclose Season 7's rest state), #2 (system-clock cheating — STRY-10 + CORE-11), #4 (tab throttling — CORE-02 + UX-10), #6 (Web Audio user-gesture — AEST-07 + Begin screen), #7 (offline catch-up — CORE-03), #10 (content/code divergence — MEMR-02 + MEMR-03 + STRY-09), #12 (anti-FOMO — UX-13 holds for every decision in Phase 2).
|
||||||
|
- `.planning/research/FEATURES.md` — must-have / should-have / defer / anti-feature classification. The "should-have" classification for Season 1 is the input to Phase 2's content authoring scope.
|
||||||
|
|
||||||
|
### Phase 1 Code Surfaces Phase 2 Will Consume
|
||||||
|
- `src/save/index.ts` — public barrel of the save layer (Phase 2 imports ONLY from this file).
|
||||||
|
- `src/save/migrations.ts` — `V1Payload` shape and migration registry. **Phase 2 extends `V1Payload` per D-34.**
|
||||||
|
- `src/save/envelope.ts` + `src/save/codec.ts` + `src/save/db.ts` + `src/save/snapshots.ts` + `src/save/persist.ts` — internal modules; Phase 2 does not import these directly.
|
||||||
|
- `src/content/loader.ts` + `src/content/schemas/index.ts` — Vite-native content pipeline. Phase 2 adds Season 1 fragment files under `/content/seasons/01-soil/` and Lura's Ink scenes under `/content/dialogue/`.
|
||||||
|
- `src/content/index.ts` — public barrel of the content layer.
|
||||||
|
- `src/game/main.ts` + `src/game/scenes/Boot.ts` — Phaser entry. Phase 2 expands the scene tree (Boot → Preloader → Garden, or simpler).
|
||||||
|
- `src/App.tsx` + `src/PhaserGame.tsx` — React shell + Phaser bridge. Phase 2 adds the Begin screen, HUD, Settings, Memory Journal, Lura dialogue overlay, and Letter overlay as React components beside the `<PhaserGame>` mount.
|
||||||
|
- `eslint.config.js` (Phase 1's flat config with `eslint-plugin-boundaries`) — enforces sim ↔ render/ui firewall. Phase 2 code MUST pass lint.
|
||||||
|
- `package.json scripts.ci` — `npm run ci` is the CI gate; Phase 2 plans must keep `npm run ci` green at every commit.
|
||||||
|
|
||||||
|
### Content Conventions
|
||||||
|
- `content/README.md` — content authoring conventions (stable string IDs, frontmatter shape, file location norms).
|
||||||
|
- `content/seasons/00-demo/fragments.yaml` — demo fragment from Phase 1. **Phase 2 removes this file** when Season 1 (`/content/seasons/01-soil/`) is authored.
|
||||||
|
|
||||||
|
### Phase 2 New Outputs (will be created during this phase)
|
||||||
|
- `/content/seasons/01-soil/` — real Season 1 fragments (Markdown + frontmatter, per MEMR-02). Fragment count and per-plant pool sizes are part of Phase 2 planning.
|
||||||
|
- `/content/dialogue/season1/` — Lura's 3 Ink scenes (arrival, mid, farewell) + the *letter from the garden* Ink passage with templated slots.
|
||||||
|
- `src/sim/numbers/big-qty.ts` (or similar) — `BigQty` wrapper around `break_eternity.js` (D-31).
|
||||||
|
- `src/store/` — Zustand 5 slices (D-32).
|
||||||
|
- `src/sim/scheduler/` — tick scheduler / monotonic clock (D-33). Single owner of wall-clock access.
|
||||||
|
- `src/sim/garden/` — garden tile state, plant state machine, harvest logic (sim-only, no DOM, no Date.now).
|
||||||
|
- `src/sim/narrative/` — Lura beat-gating logic (sim-side; reads fragment-count from sim state, not narrative-string content).
|
||||||
|
- `src/render/garden/` — Phaser scene rendering tiles, plants, ready-state pulse, gate.
|
||||||
|
- `src/ui/begin/`, `src/ui/journal/`, `src/ui/dialogue/`, `src/ui/letter/`, `src/ui/settings/` — React DOM overlays.
|
||||||
|
- `tests/e2e/` — Playwright smoke (PIPE-07) covering load → dismiss begin → plant → fast-forward → harvest → journal-shows-fragment → reload → fragment-persists.
|
||||||
|
|
||||||
|
</canonical_refs>
|
||||||
|
|
||||||
|
<code_context>
|
||||||
|
## Existing Code Insights
|
||||||
|
|
||||||
|
### Reusable Assets (from Phase 1)
|
||||||
|
- **Save layer is complete and stable** (`src/save/`). Phase 2 imports `wrap`, `unwrap`, `migrate`, `snapshot`, `listSnapshots`, `requestPersistence`, `exportToBase64`, `importFromBase64`, `openSaveDB`, `LocalStorageDBAdapter`, `crc32hex`, `canonicalJSON` from `src/save/index.ts`. The `V1Payload` interface is the contract; Phase 2 extends it (D-34).
|
||||||
|
- **Content pipeline is Vite-native** (`src/content/loader.ts`). Phase 2 drops Markdown fragments under `/content/seasons/01-soil/fragments/*.md` and they're picked up by the existing glob; schema violations fail the build.
|
||||||
|
- **ESLint boundary rule** (`eslint.config.js`) enforces `src/sim/` ↔ `src/render/`/`src/ui/` firewall. Phase 2 sim code must be pure.
|
||||||
|
- **Vitest + Playwright** are already wired (`vitest.config.ts`, `playwright.config.ts`). Phase 2 adds tests; the CI script (`npm run ci`) already runs them.
|
||||||
|
- **CRC-32 checksum + canonical JSON** for save integrity.
|
||||||
|
- **`fake-indexeddb`** is pre-installed for test environments.
|
||||||
|
- **Asset provenance gate** (`scripts/validate-assets.mjs`) — Phase 2 ships placeholder shapes via Phaser primitives, no PNG assets, so the gate is not exercised. (D-26.)
|
||||||
|
|
||||||
|
### Established Patterns (from Phase 1)
|
||||||
|
- **Single public barrel per layer** (`src/save/index.ts`, `src/content/index.ts`). Phase 2's `src/store/`, `src/sim/`, `src/render/`, `src/ui/` should each expose a `index.ts` barrel; cross-layer imports go through barrels only.
|
||||||
|
- **Stable string fragment IDs** (e.g., `season1.soil.lura_01.greeting`) — never numeric. Validated by Zod schema in `src/content/schemas/`.
|
||||||
|
- **Player-visible strings live in `/content/`**, not in TS.
|
||||||
|
- **Doc-lint pattern** (Vitest assertions over Markdown structure) — Phase 2 may extend for Lura's Ink scenes if structural invariants emerge.
|
||||||
|
- **Plan-bundle pattern** — each plan in `01-foundations-and-doctrine/` shipped a SUMMARY.md alongside its PLAN.md. Phase 2 plans should follow.
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
- **Phaser scene ↔ React overlays via Zustand 5** (D-32). Sim writes; React reads. Phaser scenes should NOT import React; React should NOT import Phaser scenes — both go through the store.
|
||||||
|
- **Tick scheduler ↔ Phaser game loop.** The sim tick runs at its own cadence (D-33); Phaser's `requestAnimationFrame` drives rendering. The scheduler dispatches sim updates from the Phaser scene's `update()` hook (or an independent loop) but is the only place `Date.now()` is allowed.
|
||||||
|
- **`visibilitychange` + `beforeunload` save triggers** wire to the save layer's `wrap` + IndexedDB write path. Phase 2 must ensure save serialization is fast enough to complete in `beforeunload`'s tight window.
|
||||||
|
- **Begin screen → AudioContext.resume()** is the bootstrapping handshake for Howler.js (Phase 3 actually uses Howler — Phase 2 may stub or no-op the audio bus while still calling `resume()`).
|
||||||
|
- **Ink → inkjs runtime path.** `inklecate` (devDependencies) compiles `.ink` → `.json` at build time; `inkjs` (dependencies) loads the JSON at runtime. Phase 2 establishes this pipeline (it's a no-op stub today per `package.json scripts.compile:ink`).
|
||||||
|
- **Memory Journal text rendering** must be DOM (React), not canvas (Phaser) — MEMR-05 demands selectable/copyable text.
|
||||||
|
|
||||||
|
</code_context>
|
||||||
|
|
||||||
|
<specifics>
|
||||||
|
## Specific Ideas
|
||||||
|
|
||||||
|
- **Tone discipline:** the user pushed back on Phase 1 ceremony and prefers minimum-viable infrastructure. Apply the same lens to Phase 2: do not build a registry, framework, or DSL where a typed function table will do; do not pre-allocate scaffolding for Phase 4+ Roots/Canopy/Storm mechanics.
|
||||||
|
- **A Dark Room rule across every UX decision:** Begin screen has no clutter; Memory Journal affordance only appears after first harvest; Settings is a small corner icon; persistence-denied is a soft toast in voice. The UI grows as the player progresses.
|
||||||
|
- **Letter is a tonal load-bearing surface, not a stat dump.** UX-02 is explicit: "written in voice, not a stat dump." The authored Ink skeleton is what holds the voice; the slots are what make it true to what happened. Reviewer should read the letter Ink as if it were short fiction, not as if it were copy.
|
||||||
|
- **The vertical slice could plausibly ship as a free standalone prologue.** This is the project's escape hatch against the 7-Season scope risk (banner concern #2). Phase 2 must complete the loop end-to-end so that, in the worst case, this slice could go live alone. That includes: a satisfying first-pass arc shape (Lura's 3 beats), a real letter, working save/restore, working e2e smoke.
|
||||||
|
- **Architecture firewall is non-negotiable.** Sim is pure; render/UI talk to sim only via the Zustand store. ESLint enforces. Tick scheduler is the *only* place wall-clock enters the sim.
|
||||||
|
- **Save-schema extension, not migration.** Phase 1's `V1Payload` has not shipped any production saves; Phase 2 extends the v1 payload shape rather than adding `migrate_v1_to_v2`. The first real migration lands in Phase 4 (per Phase 1 D-04). The synthetic v0→v1 demo migration in `migrations[1]` continues to work as the proof-of-chain.
|
||||||
|
- **Tick-count gating, not wall-time gating, for narrative beats.** STRY-10 is satisfied because Lura's fragment-count thresholds count *harvest events* (which are sim ticks), not minutes elapsed. A player who manipulates their system clock cannot fast-forward through Lura's beats.
|
||||||
|
|
||||||
|
</specifics>
|
||||||
|
|
||||||
|
<deferred>
|
||||||
|
## Deferred Ideas
|
||||||
|
|
||||||
|
Items mentioned during discussion that belong in other phases:
|
||||||
|
|
||||||
|
- **Hybrid Lura presence (gate visits + ambient text-message drip)** — discussed and rejected for Phase 2 in favor of pure discrete-gate-visits (D-12). May be reconsidered in Phase 4+ if the narrative density warrants it.
|
||||||
|
- **Plant-type unlocks tied to specific authored fragments** — discussed and rejected for Phase 2 in favor of fragment-count thresholds (D-05). Phase 4+ may explore narrative-keyed unlocks.
|
||||||
|
- **Fully procedural letter from event-log templates** — discussed and rejected (D-17). Phase 2 commits to authored skeleton + slots. If the slot vocabulary turns out to be too small in playtest, expand in Phase 4 (longer Seasons, more event types).
|
||||||
|
- **Audio sliders (UX-04), keyboard nav (UX-06), browser-zoom guarantees (UX-07), color-redundant icons (UX-08), tab-title bloom (UX-09), Lura-not-numbers UX (UX-12)** — all confirmed for **Phase 8** (D-28). Settings menu in Phase 2 is save-management only.
|
||||||
|
- **Visual regression for asset library (PIPE-04)** — Phase 8.
|
||||||
|
- **Roothold prestige currency, Season transitions, die-off, finite ceiling enforcement** — Phase 4 (Season-Prestige Cycle & Season 2). Phase 2 plants nothing in the save schema for Roothold; Phase 4 owns that addition.
|
||||||
|
- **Cross-pollination, Memory Storms, place-memory vignettes, ecosystem planting, the Below, the Loom, the Archivist, Lura's full multi-Season arc, the Nameless Man** — Phase 4–7.
|
||||||
|
- **Watercolor post-process, painted plants, painted Begin screen, solo cello + ambient buses + crossfade, reduced-motion toggle (UX-05)** — Phase 3 (Watercolor & Cello Aesthetic).
|
||||||
|
- **Real production-volume AI assets + locked north-star reference set (Phase 1 IOU AEST-09)** — Phase 5 follow-up. Phase 2 ships zero AI-generated assets (D-26 = primitive shapes); the Phase-1 IOU is unblocked, not unblocking Phase 2.
|
||||||
|
- **Real `migrate_v1_to_v2`** — Phase 4 (when Roothold / Season-prestige state actually lands). Phase 2 only extends `V1Payload` shape (D-34); no new migration entry is added.
|
||||||
|
- **Per-plant duration variance via dynamic content authoring (e.g., player-modifiable growth times)** — out of scope; not a v1 capability; not in REQUIREMENTS.md.
|
||||||
|
- **Compost yielding seeds back** — discussed as a possible scarcity mechanic and rejected (D-04 = infinite seeds). Phase 4's cross-pollination introduces hybrid seeds, which is the proper place for seed-as-economy.
|
||||||
|
- **Persistent Settings element on Begin screen** — discussed as alt access pattern; rejected in favor of in-garden corner icon + hotkey (D-29).
|
||||||
|
|
||||||
|
</deferred>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Phase: 2-season-1-vertical-slice-soil*
|
||||||
|
*Context gathered: 2026-05-09*
|
||||||
@@ -0,0 +1,311 @@
|
|||||||
|
# Phase 2: Season 1 Vertical Slice (Soil) - Discussion Log
|
||||||
|
|
||||||
|
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||||
|
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||||
|
|
||||||
|
**Date:** 2026-05-09
|
||||||
|
**Phase:** 2 — Season 1 Vertical Slice (Soil)
|
||||||
|
**Areas discussed:** Garden geometry & input · Time density (growth + offline) · Lura's Season 1 arc shape · Letter-from-the-garden composition · Begin screen treatment · Memory Journal access + layout · Visual placeholder treatment for plants · Phase 2 Settings UI scope
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Garden Geometry & Input
|
||||||
|
|
||||||
|
### Garden shape
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Small fixed grid (4×4 = 16 tiles) | Intimate walled-garden feel; matches cozy/contemplative tone and Phase 2 minimum-viable bias. | ✓ |
|
||||||
|
| Medium fixed grid (6×6 = 36 tiles) | More room to experiment and more strategic depth, but Season 1 will feel emptier with sparse early plantings and authored-content scope grows. | |
|
||||||
|
| Freeform / non-grid (5–7 named planting points) | Bespoke, painterly walled-garden feel. More work upfront and harder to cleanly extend in Seasons 2+. | |
|
||||||
|
|
||||||
|
### Seed placement input
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Click empty tile → inline seed picker | Clicking an unoccupied tile pops a small inline picker. Honors UX-01 'no UI clutter'. | ✓ |
|
||||||
|
| Persistent seed sidebar + click empty tile | More discoverable but introduces a permanent UI element that fights the A Dark Room rule. | |
|
||||||
|
| Drag-from-inventory to tile | Tactile, but more failure modes and more Phase 3 polish to feel right. | |
|
||||||
|
|
||||||
|
### Plant type count
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| 2–3 plant types | Player exercises real choice; small enough to author + concept-art under Phase 2's minimum-viable bias. | ✓ |
|
||||||
|
| Just 1 plant type | Most minimum-viable possible; risks slice feeling like a single-mechanic demo. | |
|
||||||
|
| 4–6 plant types | Richer Season 1 with more variety, but ≈4× the authored-content + concept-art surface. | |
|
||||||
|
|
||||||
|
### Seed supply
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Infinite seeds from start | Anti-FOMO; meaningful constraint is *time*, not seed inventory. | ✓ |
|
||||||
|
| Harvest yields seeds + fragment | Adds a light economy; risks turning the cozy slice into a resource-management loop. | |
|
||||||
|
| Limited starter seeds + replenish via composting | Couples composting and planting tightly; risks player feeling soft-locked. | |
|
||||||
|
|
||||||
|
### Plant unlock progression
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| First plant from start, others unlock by fragment-count | Drip-feeds discovery without ceremony. | ✓ |
|
||||||
|
| All available from start | Simplest sim; loses small but real beat of progression. | |
|
||||||
|
| Unlocks tied to specific authored fragments | Most narrative; brittle if deterministic selector reorders things. | |
|
||||||
|
|
||||||
|
### Empty tile look in Phase 2
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Faint outlined tile + subtle hover state | Readable but unembellished; Phaser primitive; no asset work. | ✓ |
|
||||||
|
| Visible 'empty plot' placeholder texture | More legible at a glance, but bakes in a visual Phase 3 will throw away. | |
|
||||||
|
| Invisible tiles (only become visible on hover) | Maximum tonal restraint; risks confusing first-time players. | |
|
||||||
|
|
||||||
|
### Post-harvest tile state
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Returns to empty + brief acknowledgement | Fastest loop, cleanest sim, honors cozy 'release' feel. | ✓ |
|
||||||
|
| Leaves a 'spent' state for a short cooldown | Adds an extra plant lifecycle state to sim and save schema. | |
|
||||||
|
| Fragment must be 'taken to the journal' first | Tactile but couples sim and UI tightly and adds dangling state. | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Time Density (Growth + Offline)
|
||||||
|
|
||||||
|
### First-plant growth duration in active play
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| ~2–5 minutes | Cozy but watchable; lets a playtest session complete the loop in ~10 minutes. | ✓ |
|
||||||
|
| ~30 seconds – 2 minutes | Demo-pace; reads less 'idle'. | |
|
||||||
|
| ~15–60 minutes | True idle; hard to playtest end-to-end without a debug fast-forward. | |
|
||||||
|
| ~6–12 hours (long-form idle) | Anchors 24h cap; risks empty active play; demands strong return-screen. | |
|
||||||
|
|
||||||
|
### Per-plant duration variance
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Vary (short / medium / longer) within band | Real time-vs-yield tradeoffs; tonal identity per plant. | ✓ |
|
||||||
|
| All identical growth times | Simplest sim; loses 'patience-is-rewarded' beat. | |
|
||||||
|
| All identical for Phase 2; vary later | Avoids re-litigating; means Season 1 plants feel interchangeable. | |
|
||||||
|
|
||||||
|
### Ready-state behavior
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Auto-harvest during offline; manual in active play | Cleanest idle-game shape; lets the letter tell a story. | ✓ |
|
||||||
|
| Wait indefinitely — manual always | Maximum agency; offline payoff feels thin. | |
|
||||||
|
| Decay if unharvested past a threshold | Adds tension and soft FOMO undercurrent — likely runs into anti-FOMO doctrine. | |
|
||||||
|
|
||||||
|
### 24h offline cap surfacing
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Capped silently in the letter's voice | Anti-FOMO; tonally consistent. | ✓ |
|
||||||
|
| Explicit cap notice in the letter | Honest about the cap; risks reading as a system message. | |
|
||||||
|
| Cap silently and never mention it | Cleanest tone; player returning after 3 days might be confused. | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lura's Season 1 Arc Shape
|
||||||
|
|
||||||
|
### Lura form
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Discrete visits at the gate | Bounded each visit; matches bible's 'she appears at the garden gate' framing. | ✓ |
|
||||||
|
| Single ongoing text-message thread | More 'friend texting,' but loses gate-arrival beat. | |
|
||||||
|
| Hybrid: gate + occasional texts between visits | Two narrative-state mechanisms; risks Phase-2 scope creep. | |
|
||||||
|
|
||||||
|
### Beat count
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| 3 beats: arrival · mid · farewell | Tight Season 1 arc; small authoring surface; load-bearing for tone. | ✓ |
|
||||||
|
| 5 beats (arrival, two mid, late, farewell) | More texture; doubles authoring + Ink-state plumbing surface. | |
|
||||||
|
| Just 1 arrival beat in Phase 2 | Simplest; Season 1 loses tonal anchor and prologue feels unfinished. | |
|
||||||
|
|
||||||
|
### Beat gating
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Fragment count thresholds (1st / 4th / 8th harvest) | Simple, content-coupled, robust to varying play sessions. STRY-10 satisfied. | ✓ |
|
||||||
|
| Specific authored-fragment IDs unlock specific beats | Most narratively rich; brittle if selector reorders things. | |
|
||||||
|
| Pure tick-count thresholds | Cleanest against STRY-10; least responsive to player action. | |
|
||||||
|
|
||||||
|
### Beat-fire UX
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Subtle gate indicator + player-initiated visit | Honors A Dark Room rule and player's pace. | ✓ |
|
||||||
|
| Auto-opens dialogue when beat fires | Disrupts gardening flow; less cozy. | |
|
||||||
|
| Queues silently; player finds Lura by clicking gate when curious | Most A-Dark-Room; risks player missing all 3 beats. | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Letter-from-the-Garden Composition
|
||||||
|
|
||||||
|
### Composition method
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Authored skeleton + templated insertions | Best balance of voice and reactivity. | ✓ |
|
||||||
|
| Fully procedural from event-log templates | Risks tonal drift; voice depends on templates not authoring. | |
|
||||||
|
| Fully hand-authored prose, conditional inclusion only | Maximum voice control; least reactive. | |
|
||||||
|
|
||||||
|
### Authoring format
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Ink (.ink files in /content/dialogue/) | Reuses STRY-06 stack — one runtime path, one tooling path. | ✓ |
|
||||||
|
| Markdown with frontmatter (in /content/letters/) | Aligns with fragment authoring; adds a second narrative-rendering path. | |
|
||||||
|
| Both — Ink for branching, Markdown for prose passages | Maximum power; introduces a third loader path. | |
|
||||||
|
|
||||||
|
### Offline event log scope
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Compact summary (counts + IDs of bloomed/harvested + any unfired Lura beat) | Compact, sufficient, bounded in size. | ✓ |
|
||||||
|
| Full ordered timeline (every state transition with timestamp) | Most powerful; biggest schema surface and storage cost. | |
|
||||||
|
| Just last/biggest event(s) | Smallest schema; letter has less to say across multiple returns. | |
|
||||||
|
|
||||||
|
### Letter UX (when shown / dismiss)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| On return after ≥5 minutes; full-screen overlay; one tap to dismiss | Avoids letter-spam; full-screen honors tonal weight. | ✓ |
|
||||||
|
| Always show on tab return regardless of duration | Most consistent; risks feeling intrusive. | |
|
||||||
|
| Inline pane (slides in from a corner) | Less disruptive; loses 'sit with this' tonal beat. | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Begin Screen Treatment
|
||||||
|
|
||||||
|
### Phase 2 vs Phase 3 split
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Tasteful placeholder; Phase 3 paints | Honors no-aesthetic-polish bias; avoids Phase 3 rework. | ✓ |
|
||||||
|
| Real painted gesture-gate now | Strongest first impression today; pulls Phase 3 work earlier and risks scope creep. | |
|
||||||
|
| Title text only (no visual treatment) | Most-A-Dark-Room; risks reading as unfinished. | |
|
||||||
|
|
||||||
|
### Subsequent-load behavior
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Every load (browser autoplay policy demands it) | Honest with browser constraints; Recommended option. | |
|
||||||
|
| Only first run; subsequent loads skip to garden + audio enables on first interaction | Smoother return; brief silent moment until first interaction. | ✓ |
|
||||||
|
| Only first run; explicit 'enable sound' prompt later | Two surfaces to maintain; risks system-message feel. | |
|
||||||
|
|
||||||
|
**Notes:** User picked the smoother-return path, accepting the brief silent moment until the first interaction as a worthwhile tradeoff for cozy pacing. CORE-05 + AEST-07 are both still satisfied — the gesture happens on first run; subsequent loads use any first interaction as the gesture.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Journal Access + Layout
|
||||||
|
|
||||||
|
### Open mechanism
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Small persistent icon + keyboard shortcut | Most discoverable without violating UX-01; Recommended option. | |
|
||||||
|
| Reveals after first harvest, then persistent | Most A-Dark-Room (UI grows as player progresses). | ✓ |
|
||||||
|
| Hidden until journal hotkey is discovered | Maximum tonal restraint; high risk players miss it. | |
|
||||||
|
|
||||||
|
### Layout
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Slide-in side panel; click a fragment to expand inline | Garden stays visible; lets player feel rooted; Recommended option. | |
|
||||||
|
| Full-screen modal overlay; back button to return to garden | More tonal weight per visit; player can't see plants ripening while reading. | ✓ |
|
||||||
|
| Dedicated 'journal view' you navigate to, like a separate room | Most narratively rich; biggest implementation lift. | |
|
||||||
|
|
||||||
|
### New-fragment surfacing in active play
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Immediate full-text reveal modal; dismiss to return to garden | Honors harvest as a small event; creates a memorable beat. | ✓ |
|
||||||
|
| Quiet deposit — small acknowledgement, find it in journal later | Most A-Dark-Room; risks player never reading the prose. | |
|
||||||
|
| Inline reveal at the harvested tile; tap to dismiss | Tactile but fragile (DOM positioned over Phaser canvas resizes). | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Visual Placeholder Treatment for Plants
|
||||||
|
|
||||||
|
### Plant look per growth stage
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Simple Phaser-primitive shape per stage, single color per type | No PNG asset work; firewall stays clean; Phase 3 swaps in painted sprites. | ✓ |
|
||||||
|
| Programmer-art sprite per stage per plant (PNG placeholders) | Differentiates more legibly; produces throwaway assets that go through provenance gate. | |
|
||||||
|
| Text labels at the tile instead of any visual | Most A-Dark-Room; reads as severe. | |
|
||||||
|
|
||||||
|
### Ready-state cue
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Subtle glow / pulse on ready tiles | Reads at a glance without text; Phase 3 paints over with warmer light. | ✓ |
|
||||||
|
| Bright color shift on the placeholder shape | Most legible; bakes a specific color Phase 3 will rework. | |
|
||||||
|
| Text indicator at tile ('ready') | Very explicit; least cozy. | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2 Settings UI Scope
|
||||||
|
|
||||||
|
### Settings UI scope
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Save management only (Export/Import + Restore prior snapshot) | Smallest scope that completes deferred Phase-1 surfaces; audio + accessibility stay in Phase 8. | ✓ |
|
||||||
|
| Save management + audio sliders | Doesn't fit 'no aesthetic polish' framing; risks dragging in keyboard nav and accessibility. | |
|
||||||
|
| No settings menu at all in Phase 2 | Smallest Phase-2 lift; deferred items still aren't player-reachable. | |
|
||||||
|
|
||||||
|
### Access
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Small icon in a corner of the main view + keyboard shortcut | Same restraint pattern as Memory Journal affordance. | ✓ |
|
||||||
|
| Hidden in a 'cog' on Begin screen + accessible from Lura's gate | Risks burying critical save-recovery affordances. | |
|
||||||
|
| Only accessible via hotkey (no visual affordance) | Risks players losing access to save recovery in a crash recovery moment. | |
|
||||||
|
|
||||||
|
### `navigator.storage.persist()` outcome surfacing
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| One-time soft toast on first save if denied; nothing if granted | Honors UX-01 + cozy tone; respects 'surfaces the result respectfully'. | ✓ |
|
||||||
|
| Always show 'persistent storage: yes/no' indicator in Settings only | Player won't know save is at risk if persistence denied. | |
|
||||||
|
| Modal dialog if denied | Strongest call to attention; reads anti-cozy. | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Claude's Discretion
|
||||||
|
|
||||||
|
Areas where the user explicitly deferred to implementation choice (full list in CONTEXT.md `<decisions>` § "Claude's Discretion"):
|
||||||
|
|
||||||
|
- Specific growth-duration values per plant within the 2–5min band.
|
||||||
|
- Exact fragment-count thresholds for plant unlocks and Lura beats (model is locked, values may shift ±1–2 in playtest).
|
||||||
|
- Form of the post-harvest acknowledgement beat (text / particle / pause).
|
||||||
|
- Form of Lura's gate indicator on beat-unlock.
|
||||||
|
- Tick rate / sim cadence (likely 4–10Hz).
|
||||||
|
- Internal Zustand store slice shapes.
|
||||||
|
- Internal Phaser scene tree.
|
||||||
|
- Specific copy of Begin screen, persistence-denied toast, post-harvest acknowledgement (must match bible voice; user reviews).
|
||||||
|
- e2e fast-forward mechanism (hidden hotkey vs URL flag vs sim-clock injection).
|
||||||
|
- Memory Journal empty-state copy.
|
||||||
|
|
||||||
|
## Deferred Ideas
|
||||||
|
|
||||||
|
Items mentioned during discussion that belong in other phases (full list in CONTEXT.md `<deferred>`):
|
||||||
|
|
||||||
|
- Hybrid Lura presence (gate + ambient drip) — possibly Phase 4+.
|
||||||
|
- Plant-type unlocks tied to specific authored fragments — possibly Phase 4+.
|
||||||
|
- Fully procedural letter from event-log templates — reconsider if slot vocabulary too small in playtest.
|
||||||
|
- Audio sliders, keyboard nav, browser-zoom guarantees, color-redundant icons, tab-title bloom, Lura-not-numbers UX — Phase 8.
|
||||||
|
- Visual regression for asset library — Phase 8.
|
||||||
|
- Roothold prestige, Season transitions, die-off, finite ceiling enforcement, cross-pollination — Phase 4.
|
||||||
|
- Memory Storms, place-memory vignettes, Nameless Man's full arc — Phase 5.
|
||||||
|
- The Below, ecosystem planting, the Loom, the Archivist — Phase 6.
|
||||||
|
- Final binary choice + credits/coda rest state — Phase 7.
|
||||||
|
- Watercolor post-process, painted plants, painted Begin screen, solo cello + ambient buses, reduced-motion toggle — Phase 3.
|
||||||
|
- Real production-volume AI assets + locked north-star reference set — Phase 5 (Phase 1 IOU AEST-09).
|
||||||
|
- Real `migrate_v1_to_v2` — Phase 4 (when Roothold lands). Phase 2 only extends `V1Payload` shape.
|
||||||
|
- Compost yielding seeds back — rejected; Phase 4's cross-pollination is the proper place for seed-as-economy.
|
||||||
|
- Persistent Settings element on Begin screen — rejected in favor of in-garden corner icon + hotkey.
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
|||||||
|
---
|
||||||
|
phase: 2
|
||||||
|
slug: season-1-vertical-slice-soil
|
||||||
|
status: filled
|
||||||
|
nyquist_compliant: true
|
||||||
|
wave_0_complete: false
|
||||||
|
created: 2026-05-09
|
||||||
|
last_updated: 2026-05-09
|
||||||
|
plan_count: 5
|
||||||
|
task_count: 15
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 2 — Validation Strategy
|
||||||
|
|
||||||
|
> Per-phase validation contract for feedback sampling during execution.
|
||||||
|
> Populated by the planner during plan generation. Each plan's tasks declare automated verification commands or a Wave-0 dependency.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test Infrastructure
|
||||||
|
|
||||||
|
| Property | Value |
|
||||||
|
|----------|-------|
|
||||||
|
| **Framework** | Vitest 4.x (sim + unit + integration) + Playwright 1.x (e2e smoke, PIPE-07) |
|
||||||
|
| **Config files** | `vitest.config.ts`, `playwright.config.ts` (Phase 1 already shipped both) |
|
||||||
|
| **Quick run command** | `npm test` (Vitest only — happy-dom env; ~2–4s on warm cache as Phase-2 surface grows) |
|
||||||
|
| **Full suite command** | `npm run ci` (lint + Vitest + validate:assets + build + check:bundle-split) |
|
||||||
|
| **Playwright command** | `npm run test:e2e` (= `npx playwright test`; Phase 2 ships the first real e2e) |
|
||||||
|
| **Estimated runtime** | Vitest ≤8s · Playwright ≤30s · `npm run ci` ≤90s |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sampling Rate
|
||||||
|
|
||||||
|
- **After every task commit:** Run `npm test` (Vitest)
|
||||||
|
- **After every plan wave:** Run `npm run ci` (full)
|
||||||
|
- **Before `/gsd-verify-work`:** `npm run ci` AND `npx playwright test` must be green
|
||||||
|
- **Max feedback latency:** ≤8 seconds for Vitest; ≤30s for Playwright
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Per-Task Verification Map
|
||||||
|
|
||||||
|
> Every PLAN task's automated verification command, mapped to a phase REQ-ID and any threat-model entry.
|
||||||
|
|
||||||
|
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|
||||||
|
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
|
||||||
|
| 02-01-T1 | 02-01 | 0 | CORE-02, CORE-03, CORE-11, UX-11 | T-02-01-02, T-02-01-03, T-02-01-05 | drainTicks refuses negative; clamps 24h; benchmark <500ms | unit | `npm run lint && npx vitest run src/sim/numbers/ src/sim/scheduler/ && npm run build` | Plan 02-01 creates | ⬜ pending |
|
||||||
|
| 02-01-T2 | 02-01 | 0 | UX-10 | T-02-01-01, T-02-01-04 | save lifecycle hooks fire synchronously on visibilitychange/beforeunload/season-transition | unit + integration | `npm run lint && npx vitest run src/store/ src/save/migrations.test.ts src/save/lifecycle.test.ts && npm run ci` | Plan 02-01 creates | ⬜ pending |
|
||||||
|
| 02-01-T3 | 02-01 | 0 | (defended option) | T-02-01-04 | ESLint blocks Date.now() outside scheduler/clock.ts | unit (lint integration) | `npm run lint && npx vitest run src/sim/__test_violation__/ && npm run ci` | Plan 02-01 creates | ⬜ pending |
|
||||||
|
| 02-02-T1 | 02-02 | 1 | GARD-01, GARD-02, CORE-02 | — | sim/garden pure; growth state machine deterministic | unit | `npm run lint && npx vitest run src/sim/garden/ && npm run build` | Plan 02-02 creates | ⬜ pending |
|
||||||
|
| 02-02-T2 | 02-02 | 1 | GARD-01, GARD-02, CORE-02 | T-02-02-01 | render layer + Garden scene wires scheduler + EventBus + store | manual + build | `npm run lint && npm run build` (manual smoke: `npm run dev` confirms tile grid + plant primitives visible) | Plan 02-02 creates | ⬜ pending |
|
||||||
|
| 02-02-T3 | 02-02 | 1 | AEST-07, UX-01, GARD-01 | T-02-02-02, T-02-02-03 | BeginScreen + audio bootstrap synchronous in click; SeedPicker enqueues plantSeed; UI strings externalized | integration | `npm run lint && npx vitest run src/ui/begin/ src/ui/garden/ src/content/ && npm run ci` | Plan 02-02 creates | ⬜ pending |
|
||||||
|
| 02-03-T1 | 02-03 | 1 | GARD-03, GARD-04, MEMR-01, MEMR-02, MEMR-03, MEMR-06 | T-02-03-02, T-02-03-04 | selector deterministic + gating + no-dup + exhaustion fallback; ≥10 fragments authored; harvest/compost pure | unit + build | `npm run lint && npx vitest run src/sim/memory/ src/sim/garden/ src/content/ && npm run build` | Plan 02-03 creates | ⬜ pending |
|
||||||
|
| 02-03-T2 | 02-03 | 1 | MEMR-04, MEMR-05, UX-01 | T-02-03-03 | Journal DOM selectable + reveal-modal + journal-icon-after-first-harvest | integration | `npm run lint && npx vitest run src/ui/journal/ && npm run ci` | Plan 02-03 creates | ⬜ pending |
|
||||||
|
| 02-03-T3 | 02-03 | 1 | PIPE-02 | T-02-03-05 | check-bundle-split.mjs asserts Vite emits a Season-1 chunk | structural | `npm run lint && npm run build && node scripts/check-bundle-split.mjs && npx vitest run scripts/check-bundle-split.test.mjs && npm run ci` | Plan 02-03 creates | ⬜ pending |
|
||||||
|
| 02-04-T1 | 02-04 | 2 | STRY-06 | T-02-04-03, T-02-04-04 | inklecate compiles 4 .ink → JSON; ink-loader instantiates Story + binds variables snake_case | unit + build | `npm run compile:ink && npm run lint && npx vitest run src/content/ink-loader.test.ts scripts/compile-ink.test.mjs && npm run ci` | Plan 02-04 creates | ⬜ pending |
|
||||||
|
| 02-04-T2 | 02-04 | 2 | STRY-01, STRY-10 | T-02-04-01, T-02-04-06 | lura-gate fires on harvest count 1/4/8 only; FakeClock advance alone does NOT fire (STRY-10) | unit | `npm run lint && npx vitest run src/sim/narrative/ src/sim/garden/ && npm run build` | Plan 02-04 creates | ⬜ pending |
|
||||||
|
| 02-04-T3 | 02-04 | 2 | STRY-01, STRY-06, STRY-07 | T-02-04-03 | LuraDialogue + InkRenderer + gate-renderer wired; pending beat opens overlay; resolves on close | integration | `npm run lint && npx vitest run src/ui/dialogue/ src/render/ && npm run ci` | Plan 02-04 creates | ⬜ pending |
|
||||||
|
| 02-05-T1 | 02-05 | 2 | UX-02, GARD-04, CORE-03 | T-02-05-02, T-02-05-08 | sim/offline + auto-harvest + letter Ink + letter-renderer all pure | unit + build | `npm run compile:ink && npm run lint && npx vitest run src/sim/offline/ src/sim/garden/auto-harvest.test.ts src/ui/letter/letter-renderer.test.ts && npm run ci` | Plan 02-05 creates | ⬜ pending |
|
||||||
|
| 02-05-T2 | 02-05 | 2 | UX-02, UX-10, CORE-09 | T-02-05-01, T-02-05-03, T-02-05-04 | Letter overlay (Pitfall 9 audio bootstrap on dismiss) + Settings (Export/Import/Restore) + boot-path save lifecycle | integration | `npm run lint && npx vitest run src/ui/letter/ src/ui/settings/ && npm run ci` | Plan 02-05 creates | ⬜ pending |
|
||||||
|
| 02-05-T3 | 02-05 | 2 | PIPE-07 | T-02-05-01 | Playwright e2e covering load → begin → plant → fast-forward → harvest → reveal → journal → reload → persist | e2e | `npm run ci && npx playwright test tests/e2e/season1-loop.spec.ts` | Plan 02-05 creates | ⬜ pending |
|
||||||
|
|
||||||
|
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wave 0 Requirements
|
||||||
|
|
||||||
|
Wave 0 (Plan 02-01) lands BigQty, the Zustand 5 store, the tick scheduler, and the Phase-2 V1Payload schema extension before any vertical slice can run. Until Wave 0 lands, every Wave-1+ task carries a Wave-0 dependency.
|
||||||
|
|
||||||
|
- [ ] `src/sim/numbers/big-qty.ts` + `big-qty.test.ts` — BigQty wrapper unit tests
|
||||||
|
- [ ] `src/sim/numbers/format.ts` + `format.test.ts` — UX-11 thresholds
|
||||||
|
- [ ] `src/sim/scheduler/clock.ts` + `clock.test.ts` — FakeClock fixture; Date.now() owner
|
||||||
|
- [ ] `src/sim/scheduler/tick.ts` + `tick.test.ts` — drainTicks, accumulator, CORE-02
|
||||||
|
- [ ] `src/sim/scheduler/catchup.ts` + `catchup.test.ts` — 24h clamp + negative refusal (CORE-03 + CORE-11)
|
||||||
|
- [ ] `src/store/store.ts` + `store.test.ts` — Zustand 5 vanilla createStore + 4 slices
|
||||||
|
- [ ] `src/store/sim-adapter.ts` — slim sim → store adapter (sim never imports the store directly)
|
||||||
|
- [ ] `src/save/migrations.ts` — extended V1Payload with unlockedPlantTypes / luraBeatProgress / offlineEvents / settings.persistenceToastShown (Phase-2 schema EXTENSION, not v1→v2)
|
||||||
|
- [ ] `src/save/lifecycle.ts` + `lifecycle.test.ts` — UX-10 hooks (visibilitychange + beforeunload + saveOnSeasonTransition)
|
||||||
|
- [ ] `src/game/event-bus.ts` — Phaser.Events.EventEmitter singleton (per Phaser 4 React-template pattern)
|
||||||
|
- [ ] `eslint.config.js` — additional sim-purity rule banning `Date.now`/`setInterval` in `src/sim/**` (defended option; Plan 02-01 Task 3 ships)
|
||||||
|
|
||||||
|
*Filled in by Plan 02-01. Plans 02-02..02-05 declare a Wave-0 dependency in frontmatter (`depends_on: [02-01, ...]`).*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Manual-Only Verifications
|
||||||
|
|
||||||
|
| Behavior | Requirement | Why Manual | Test Instructions |
|
||||||
|
|----------|-------------|------------|-------------------|
|
||||||
|
| AudioContext.resume() actually unlocks audio across Chrome / Firefox / Safari / Edge | AEST-07 | Browser autoplay policies vary; Vitest happy-dom does not exercise real audio context. | After Plan 02-02 lands, manually load the dev build in Chrome / Firefox / Safari (last 2 stable). Click Begin. Confirm a console-logged `audioContext.state === 'running'`. |
|
||||||
|
| Letter prose reads in voice (not as a stat dump) | UX-02 | Tonal verification is a human review; CONTEXT D-17 explicitly calls this out. | Author reviews `/content/dialogue/season1/letter-from-the-garden.ink` against the bible voice; reviewer signs off in Plan 02-05 SUMMARY. |
|
||||||
|
| Cozy 2–5min growth feels right at playtest | CONTEXT D-08 / D-09 | Subjective pacing — only verifiable by playing. | Solo playtest after Plan 02-05 lands. Adjust per-plant durations if either pace is off; record final values in SUMMARY. |
|
||||||
|
| Lura's three beats read in voice + warmth-anchor tone | STRY-01 + CLAUDE.md Tone | Tonal verification. | After Plan 02-04 lands, user reads compiled Lura beats in dev build during a real harvest cadence. Sign-off in Plan 02-04 SUMMARY. |
|
||||||
|
| Tile→DOM coord mapping under Phaser.Scale.FIT | RESEARCH Assumption A5 (MEDIUM) | Layout depends on actual canvas DOMRect; test in non-fullscreen window. | Plan 02-02 Task 2 manual smoke: dev build → click empty tile → seed picker positioned visually over the tile in non-fullscreen + fullscreen. |
|
||||||
|
| inklecate compiles cleanly on Windows + macOS + Linux | RESEARCH Assumption A6 (MEDIUM) | First real inklecate invocation in the project. | Plan 02-04 Task 1 first run on the dev machine; cross-platform verified post-merge via CI run. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Validation Sign-Off
|
||||||
|
|
||||||
|
- [x] All tasks have `<automated>` verify or Wave 0 dependencies
|
||||||
|
- [x] Sampling continuity: no 3 consecutive tasks without automated verify (every task above has a non-empty `Automated Command`)
|
||||||
|
- [x] Wave 0 covers all MISSING references (Plan 02-01 Tasks 1+2 land all foundations Plans 02-02..02-05 depend on)
|
||||||
|
- [x] No watch-mode flags (`vitest run`, not `vitest`)
|
||||||
|
- [x] Feedback latency < 8s for Vitest, < 30s for Playwright
|
||||||
|
- [x] `nyquist_compliant: true` set in frontmatter (set by the planner after the per-task map filled)
|
||||||
|
|
||||||
|
**Approval:** approved (planner)
|
||||||
Reference in New Issue
Block a user