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>
This commit is contained in:
@@ -1,10 +1,181 @@
|
||||
# /content/seasons/01-soil/fragments.yaml
|
||||
#
|
||||
# Phase 2 placeholder. Plan 02-03 replaces with the authored Season-1
|
||||
# fragments (≥10 in voice, MEMR-* coverage). The single placeholder
|
||||
# fragment here keeps the eager fragment loader green during Plan 02-02
|
||||
# (Plan 02-03 expands the file).
|
||||
# Phase 2 Plan 02-03 — Season 1 ("Soil") authored fragment pool.
|
||||
#
|
||||
# Bible voice (CLAUDE.md "Tone"): warm, specific, intermittent, sometimes
|
||||
# funny, sometimes devastating. Lura is the warmth anchor (Plan 02-04);
|
||||
# Phase 2 Wave 1 ships the gardener-keeper voice — the contrast, not a
|
||||
# co-griever.
|
||||
#
|
||||
# Tag tonal registers (Plan 02-03 extension to FragmentSchema):
|
||||
# warm — light, mundane, sometimes funny (rosemary pool)
|
||||
# contemplative — quiet weight, the shape of an absence (yarrow pool)
|
||||
# heavy — clear-eyed grief; never melodrama (winter-rose pool)
|
||||
# _meta — selector-only sentinel; the gated pool excludes this tag
|
||||
#
|
||||
# Pool depth (Plan W6 fix): a worst-case all-rosemary playthrough must not
|
||||
# exhaust the warm pool before the 8th harvest (Lura's farewell threshold,
|
||||
# CONTEXT D-14). The warm pool below ships ≥9 entries for the 1-buffer
|
||||
# safety margin. The exhaustion sentinel `season1.soil._exhaustion` is a
|
||||
# defensive fallback (RESEARCH Pitfall 8); under normal Phase-2 play it is
|
||||
# unreachable.
|
||||
#
|
||||
# IDs match /^season1\.[a-z0-9._-]+$/ (FragmentSchema regex; CLAUDE.md
|
||||
# stable-string-ID rule). IDs are forever — once shipped, only the body
|
||||
# may change, never the id.
|
||||
|
||||
fragments:
|
||||
- id: season1.soil.placeholder
|
||||
# ----- WARM tonal register (rosemary pool) -----
|
||||
- id: season1.soil.first-bloom
|
||||
season: 1
|
||||
body: "(placeholder — Plan 02-03 ships authored fragments)"
|
||||
tags: [warm]
|
||||
body: |
|
||||
The first thing that grew was rosemary. The shape of it didn't matter
|
||||
so much as the smell — sharp, the kind of green that means the air
|
||||
will warm up by afternoon.
|
||||
|
||||
- id: season1.soil.bread-was-easy
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
Someone, in the place this came from, was very good at bread. There
|
||||
isn't a name attached. There is the shape of an oven door, and a
|
||||
towel folded a particular way.
|
||||
|
||||
- id: season1.soil.the-cat
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
The cat is missing now too. It used to walk along the wall at dusk.
|
||||
It would not come when called. It came anyway, in its own time. Most
|
||||
good things were like that.
|
||||
|
||||
- id: season1.soil.kettle-on-the-hob
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
A kettle, a little dented on one side, lived on a stove that no
|
||||
longer exists. It whistled flat — half a step under the note it was
|
||||
meant to make. Nobody ever fixed it. Nobody ever needed to.
|
||||
|
||||
- id: season1.soil.the-wrong-song
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
Someone in the kitchen used to sing a song with the words mostly
|
||||
wrong. They would commit to the wrong words anyway, full voice. It
|
||||
was funnier each time. The garden has the rhythm but not the words.
|
||||
|
||||
- id: season1.soil.the-jam-summer
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
There was a summer where someone made too much jam. Apricot, mostly.
|
||||
The cupboards filled. People came over and were given jam. Strangers
|
||||
were given jam. It became a small embarrassment, and then a joke,
|
||||
and then a kindness people remembered for a long time after.
|
||||
|
||||
- id: season1.soil.boots-by-the-door
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
Two pairs of boots used to sit by a door. One pair larger, one pair
|
||||
smaller. They were left muddy more often than not. Whoever it was
|
||||
that minded the mud, in the end, did not really mind it.
|
||||
|
||||
- id: season1.soil.the-good-spoon
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
Every kitchen has a good spoon. The one you reach for without
|
||||
thinking. This one was wooden, with a small burn mark on the handle
|
||||
from a moment of inattention years ago. It outlasted the inattentive
|
||||
person. Some objects are like that.
|
||||
|
||||
- id: season1.soil.the-laughing-fit
|
||||
season: 1
|
||||
tags: [warm]
|
||||
body: |
|
||||
A laughing fit at a funeral. The kind that makes things worse and
|
||||
better at once. It started over something nobody could later
|
||||
identify. They were all forgiven. Mostly by themselves, after a
|
||||
decent interval.
|
||||
|
||||
# ----- CONTEMPLATIVE tonal register (yarrow pool) -----
|
||||
- id: season1.soil.what-the-wind-was-for
|
||||
season: 1
|
||||
tags: [contemplative]
|
||||
body: |
|
||||
The wind used to mean something specific in spring — a person putting
|
||||
sheets out to dry, the line across two posts, the way it would crack
|
||||
like a small flag. That meaning has gone soft. The wind still blows.
|
||||
|
||||
- id: season1.soil.the-letter-not-sent
|
||||
season: 1
|
||||
tags: [contemplative]
|
||||
body: |
|
||||
There was a letter someone meant to send. The address is gone, the
|
||||
ink is gone, the reason is gone. What remains is the silence on the
|
||||
other side of it — a room, somewhere, that never received the news.
|
||||
|
||||
- id: season1.soil.numbers-in-the-margin
|
||||
season: 1
|
||||
tags: [contemplative]
|
||||
body: |
|
||||
A book had a number written in the margin: 47. Whose age, whose page,
|
||||
whose count of something — gone. The 47 sits very calmly on the
|
||||
paper. Numbers are the last to forget. They will outlast all of us.
|
||||
|
||||
- id: season1.soil.the-clock-that-stopped
|
||||
season: 1
|
||||
tags: [contemplative]
|
||||
body: |
|
||||
A clock on a mantel stopped at 4:18. Nobody wound it again. It was
|
||||
not a meaningful hour. It was the hour the hand happened to be on
|
||||
when nobody was looking. Now it is the only hour, forever, in that
|
||||
one small place.
|
||||
|
||||
# ----- HEAVY tonal register (winter-rose pool) -----
|
||||
- id: season1.soil.the-name-she-used
|
||||
season: 1
|
||||
tags: [heavy]
|
||||
body: |
|
||||
She had a name for him that wasn't his name. He had stopped objecting
|
||||
to it long before the end. After, the name kept arriving — at the
|
||||
door, in the post, in the mouths of people who had heard it once and
|
||||
never been corrected. The garden does not say it. The garden only
|
||||
grows.
|
||||
|
||||
- id: season1.soil.what-the-snow-took
|
||||
season: 1
|
||||
tags: [heavy]
|
||||
body: |
|
||||
Snow took the orchard one March. The trees were already old. The
|
||||
orchard had been someone's grandfather's, then someone's father's,
|
||||
then a row of stumps and a few unrooted sticks pretending. Pretending
|
||||
is also a kind of remembering, until one day it isn't.
|
||||
|
||||
- id: season1.soil.the-quiet-after
|
||||
season: 1
|
||||
tags: [heavy]
|
||||
body: |
|
||||
There is a quiet that comes after, that is not the same as the quiet
|
||||
that came before. The room is the same. The light is the same. The
|
||||
quiet is differently shaped — slightly larger than the room, somehow.
|
||||
Nobody needs to explain this to anyone who has felt it.
|
||||
|
||||
# ----- EXHAUSTION FALLBACK (RESEARCH Pitfall 8) -----
|
||||
# Returned ONLY when the gated pool is empty. The pool excludes anything
|
||||
# tagged `_meta`; selector.ts looks this id up explicitly via
|
||||
# EXHAUSTION_FALLBACK_ID. In normal Phase-2 play this is unreachable
|
||||
# (the warm pool is sized to outlast the 8th-harvest Lura threshold),
|
||||
# but the sentinel is the documented "behavior chosen" for the
|
||||
# gated-pool-exhaustion case and is committed to the corpus so the
|
||||
# selector has something to return rather than null.
|
||||
- id: season1.soil._exhaustion
|
||||
season: 1
|
||||
tags: [_meta]
|
||||
body: |
|
||||
The garden knows this one already. The light comes in the same way it
|
||||
came yesterday. There will be a new thing tomorrow. There is also
|
||||
this — the steady part, that does not need re-learning.
|
||||
|
||||
Reference in New Issue
Block a user