Commit Graph

2 Commits

Author SHA1 Message Date
josh f192e8298c feat(02-03): Season-1 fragments + sim/memory selector + harvest/compost commands
Task 1 of Plan 02-03: ship Season-1 authored content + the deterministic
fragment selector + extend sim/garden/commands.ts with harvest + compost.

Content (≥17 Season-1 fragments under /content/seasons/01-soil/):
- 14 in fragments.yaml (9 warm / 3 contemplative / 2 heavy + 1 _meta sentinel)
- 2 long-form Markdown fragments (lura-first-letter.md, winter-rose-night.md)
- Pool depth (W6): warm pool ≥9 satisfies the worst-case all-rosemary
  playthrough at the 8th-harvest Lura threshold (CONTEXT D-14)
- All ids match /^season1\.[a-z0-9._-]+$/ (FragmentSchema regex; CLAUDE.md
  stable-string-ID rule); bible voice maintained throughout

FragmentSchema extension (back-compat — tags is optional):
- Optional `tags: z.array(z.string()).optional()` for tonal-register gating
- Reserved tag `_meta` excludes the exhaustion sentinel from the normal pool

src/sim/memory/ (new module):
- pool.ts — filterPool() pure helper (Season + tonal-register + no-dup gates)
- selector.ts — selectFragment() deterministic + mulberry32 PRNG +
  EXHAUSTION_FALLBACK_ID for Pitfall 8 fallback
- selector.test.ts — 16 tests covering gating / no-dup / determinism /
  sentinel-fallback / sentinel-exclusion-from-normal-pool
- index.ts — barrel; src/sim/index.ts re-exports

src/sim/garden/commands.ts (extended):
- harvest() pure command — empties tile, appends one fragment id,
  re-computes unlockedPlantTypes (Pitfall 10: thresholds checked AFTER
  the harvest commit). Refuses immature plants and OOR indices.
- compost() pure command — empties tile regardless of stage; no fragment
  yield (D-07); no resource refund (D-04 = infinite seeds).
- SimContext interface — application-layer-injected (fragments, currentSeason)
- simulateOneTick() takes optional ctx (default empty pool); harvest/compost
  branches added to the kind switch.
- BLOCKER 3 invariant preserved — sim writes tickCount, never lastTickAt.

Plant-type unlock thresholds (CONTEXT D-05, plan author's discretion):
- rosemary @ count 0 (start)
- yarrow @ count 3 (third harvest)
- winter-rose @ count 6 (sixth harvest)

commands.test.ts: +18 new cases (harvest / compost / Pitfall 10 boundary
on yarrow + winter-rose / sentinel fallback / immutability). 65/65 tests
green across src/sim/memory + src/sim/garden + src/content; lint exits 0;
build green (Vite parses all 17 fragments without schema violation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 10:00:38 -04:00
josh e82a11b988 feat(02-02): sim/garden — types, plants table, growth state machine, plantSeed
- src/sim/garden/types.ts: Tile/PlantInstance/PlantType/PlantTypeId/GrowthStage interfaces; tileIdx(row,col) + tileCoords(idx) + emptyTiles() helpers (RESEARCH Pitfall 2 canonical row*4+col encoding)
- src/sim/garden/plants.ts: 3 Season-1 plants per D-03 (rosemary 600t / yarrow 900t / winter-rose 1500t — D-08/D-09 2–5min band) with placeholder tints (D-26)
- src/sim/garden/growth.ts: advanceGrowth() pure function — Sprout (0%) → Mature (33%) → Ready (100%); Math.max clamp on negative deltas defends Pitfall 1 system-clock rewind
- src/sim/garden/commands.ts: plantSeed (D-05 unlock-gate + occupied silent no-op + immutability) + simulateOneTick (BLOCKER 3 — writes tickCount, NEVER lastTickAt) + tileGrowthStage helper
- src/sim/garden/index.ts: barrel
- src/sim/index.ts: re-export garden barrel
- 25 new tests (11 growth + 14 commands) — all green; lint clean; build green
- ESLint sim-purity rule from Plan 02-01 confirms zero Date.now/setInterval call sites under src/sim/garden/
2026-05-09 09:32:59 -04:00