Files
josh 69964ba17f docs(02): capture phase context
Phase 2 (Season 1 Vertical Slice — Soil) discuss-phase output. 02-CONTEXT.md
captures 34 implementation decisions across 8 gray areas (garden geometry &
input · time density · Lura's arc · letter composition · Begin screen ·
Memory Journal · plant placeholders · Phase-2 Settings UI scope). Locks the
4×4 grid + click+inline seed picker, 2–5min growth band per plant with
auto-harvest-while-offline, 3 Lura gate visits gated by 1st/4th/8th harvest,
authored Ink letter skeleton with templated slots, full-screen letter on
≥5min absence, tasteful placeholder Begin screen (Phase 3 paints), full-
screen Journal modal revealing after first harvest, simple Phaser-primitive
plants with subtle ready-state pulse, save-management-only Settings.
Phase 2's first commits: BigQty wrapper, Zustand 5 store, tick scheduler.
Save schema is a v1 *extension*, not v1→v2.

02-DISCUSSION-LOG.md preserves the alternatives considered for human review.

Next: /gsd-plan-phase 2

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 01:39:48 -04:00

27 KiB
Raw Permalink Blame History

Phase 2: Season 1 Vertical Slice (Soil) - Context

Gathered: 2026-05-09 Status: Ready for planning

## 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.

## 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: 23 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 12 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 = ~25 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 ~25min 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 410Hz 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 25min 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 ±12 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 410Hz; 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).

<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 110, 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.tsV1Payload 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.cinpm 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>

## 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.
## 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 47.
  • 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).

Phase: 2-season-1-vertical-slice-soil Context gathered: 2026-05-09