docs(02-04): complete lura-gate-beats plan
- 02-04-lura-gate-beats-SUMMARY.md created. Documents: - 3 Lura Ink beats authored in bible voice (warmth anchor, contrast not co-griever) - Build-time inklecate compile pipeline with bundled binary (BLOCKER 4 mitigated) - RESEARCH Assumption A6 verified first-try on Windows - 47 new Vitest cases (264/264 total green); npm run ci exits 0 - sim/narrative gating pure-state; STRY-10 mechanically defended - sim/* contains zero inkjs imports; ESLint sim-purity rule still green - 4 lazy code-split chunks emitted for compiled Ink JSON - Compost-toast UI deferred to Plan 02-05 (folded into persistence-toast surface) - 5 auto-fix deviations documented (Rule 1 + Rule 3); 2 tightenings; 0 architectural changes - STATE.md updated: progress 18% → 19%; Phase 2 plans 3/5 → 4/5; 217 → 264 tests; per-phase metrics updated (Phase 2 4/5 plans, ~66min, ~16min/plan). - ROADMAP.md: Plan 02-04 marked complete with duration; progress table updated. - REQUIREMENTS.md: STRY-01 / STRY-06 / STRY-07 / STRY-10 marked complete with full traceability annotations. Plan 02-05 (offline catchup + letter + Settings + Playwright e2e) is the only remaining Phase-2 work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,16 +49,16 @@ Requirements for initial release. Each maps to roadmap phases. All are user-cent
|
||||
|
||||
### STORY — Characters, Dialogue, Choice
|
||||
|
||||
- [ ] **STRY-01**: Lura (the audience-surrogate carpenter from a Remembered town) appears at the garden gate during Season 1 and reacts to early fragments with text-message-cadence dialogue authored in Ink.
|
||||
- [x] **STRY-01**: Lura (the audience-surrogate carpenter from a Remembered town) appears at the garden gate during Season 1 and reacts to early fragments with text-message-cadence dialogue authored in Ink. <!-- Plan 02-04: 3 authored Ink beats (lura-arrival/mid/farewell.ink) under /content/dialogue/season1/, fired at 1st/4th/8th harvest (D-14); src/sim/narrative/lura-gate.ts gates on harvestedFragmentIds.length; src/ui/dialogue/LuraDialogue.tsx renders lines via inkjs Story + InkRenderer drip cadence (1500ms base + 20ms/char, capped 4000ms); render/garden/gate-renderer.ts visual cue. 17 sim tests + 13 dialogue tests green. -->
|
||||
- [ ] **STRY-02**: Lura's dialogue continues across all 7 Seasons, contextualizes major story beats, and reflects player progression in Ink-driven branches tied to Zustand variables.
|
||||
- [ ] **STRY-03**: The Nameless Man appears in Season 2, his dialogue progressively shortens and confuses across Seasons 2-4, and he vanishes mid-sentence in Season 4 with no fanfare or cutscene.
|
||||
- [ ] **STRY-04**: The Archivist appears in Season 6, never gendered (they/them), speaks softly and reflectively, and asks the player a thematic question without forcing an answer.
|
||||
- [ ] **STRY-05**: The Archivist responds (mechanically and tonally) when the player feeds the Loom a memory containing both joy and grief — the Loom holds the contradiction, ending the Unremembering's advance.
|
||||
- [ ] **STRY-06**: All authored dialogue uses Ink (`.ink` files) compiled to JSON for runtime via inkjs.
|
||||
- [ ] **STRY-07**: The Keeper (player character) has no name, no backstory, and no dialogue beyond the final binary choice in Season 7.
|
||||
- [x] **STRY-06**: All authored dialogue uses Ink (`.ink` files) compiled to JSON for runtime via inkjs. <!-- Plan 02-04: scripts/compile-ink.mjs invokes the bundled inklecate binary at build time (BLOCKER 4 — uses node_modules/inklecate/bin); 4 .ink → .ink.json compiled deterministically; src/content/ink-loader.ts lazy-loads compiled JSON via import.meta.glob and instantiates inkjs.Story; npm run ci runs compile:ink before tests + before build. RESEARCH Assumption A6 verified first-try on Windows. -->
|
||||
- [x] **STRY-07**: The Keeper (player character) has no name, no backstory, and no dialogue beyond the final binary choice in Season 7. <!-- Plan 02-04: vacuously satisfied for Phase 2 — zero Ink files contain Keeper-spoken lines. The Keeper is the player; only Lura speaks (and the gardener-keeper voice acknowledges in compost beats, but is never personified as a named character). Phase 7 (SEAS-09 / STRY-08) lands the binary choice surface. -->
|
||||
- [ ] **STRY-08**: The final scene of Season 7 presents the player with a binary narrative choice (*"They help us remember"* / *"They help us grow"*); both endings display the line *"The garden persists."* and both are tonally complete; neither unlocks alternate post-credits content.
|
||||
- [x] **STRY-09**: Every player-visible string is externalized in `/content/` (not hardcoded in TypeScript), so localization can be retrofitted in v2 without code refactor. <!-- Plan 01-04: /content/ convention established; no player-visible strings in Phase 1 source (vacuously satisfied); real enforcement lands Phase 2. -->
|
||||
- [ ] **STRY-10**: Story progression gates on tick count, not on wall time — players cannot fast-forward through authored beats by manipulating their system clock.
|
||||
- [x] **STRY-10**: Story progression gates on tick count, not on wall time — players cannot fast-forward through authored beats by manipulating their system clock. <!-- Plan 02-04: src/sim/narrative/lura-gate.ts gates on state.harvestedFragmentIds.length (sim-internal counter), never wall time. The gate function takes only the harvest count as input — no clock parameter exists. The STRY-10 test case in lura-gate.test.ts advances FakeClock by 24 hours with zero harvests and confirms no beat fires. ESLint sim-purity rule (Block 3 of eslint.config.js) mechanically prevents Date.now/setInterval inside src/sim/narrative/. -->
|
||||
|
||||
### SEAS — Seasons, Prestige, Roothold
|
||||
|
||||
@@ -223,16 +223,16 @@ Populated by gsd-roadmapper during roadmap creation on 2026-05-08. Updated after
|
||||
| MEMR-05 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-03; Journal + FragmentRevealModal render fragment bodies in <pre> with userSelect:'text'; pinned by computed-style assertions) |
|
||||
| MEMR-06 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-03; src/sim/memory/selector.ts deterministic via mulberry32 seeded from sim state; gated by Season + plant-type tonal register; no-dup; sentinel fallback for Pitfall 8) |
|
||||
| MEMR-07 | Phase 5 — Seasons 3-4 (Canopy & Storm) | Pending |
|
||||
| STRY-01 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
|
||||
| STRY-01 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-04; 3 Ink beats authored at /content/dialogue/season1/lura-{arrival,mid,farewell}.ink, gated at 1/4/8 harvests via sim/narrative/lura-gate.ts; LuraDialogue overlay renders inkjs Story with text-message cadence) |
|
||||
| STRY-02 | Phase 7 — Season 7 (Return) & Final Choice | Pending |
|
||||
| STRY-03 | Phase 5 — Seasons 3-4 (Canopy & Storm) | Pending |
|
||||
| STRY-04 | Phase 6 — Seasons 5-6 (Depth & Loom) | Pending |
|
||||
| STRY-05 | Phase 6 — Seasons 5-6 (Depth & Loom) | Pending |
|
||||
| STRY-06 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
|
||||
| STRY-07 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
|
||||
| STRY-06 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-04; scripts/compile-ink.mjs invokes bundled inklecate binary; src/content/ink-loader.ts lazy-loads compiled JSON; npm run ci compiles before tests + build. Assumption A6 verified) |
|
||||
| STRY-07 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-04; vacuously satisfied — zero Keeper-spoken lines in Phase 2 .ink files; Phase 7 lands the binary choice surface) |
|
||||
| STRY-08 | Phase 7 — Season 7 (Return) & Final Choice | Pending |
|
||||
| STRY-09 | Phase 1 — Foundations & Doctrine | Complete (vacuous — /content/ convention established; no player-visible strings in Phase 1 source) |
|
||||
| STRY-10 | Phase 2 — Season 1 Vertical Slice (Soil) | Pending |
|
||||
| STRY-10 | Phase 2 — Season 1 Vertical Slice (Soil) | Complete (Plan 02-04; lura-gate gates on harvest count not wall time; STRY-10 test case advances FakeClock 24h with 0 harvests and confirms no beat fires; ESLint sim-purity rule prevents Date.now in src/sim/narrative/) |
|
||||
| SEAS-01 | Phase 4 — Season-Prestige Cycle & Season 2 (Roots) | Pending |
|
||||
| SEAS-02 | Phase 4 — Season-Prestige Cycle & Season 2 (Roots) | Pending |
|
||||
| SEAS-03 | Phase 4 — Season-Prestige Cycle & Season 2 (Roots) | Pending |
|
||||
|
||||
Reference in New Issue
Block a user