diff --git a/docs/phase-16-plan.md b/docs/phase-16-plan.md new file mode 100644 index 0000000..b116f68 --- /dev/null +++ b/docs/phase-16-plan.md @@ -0,0 +1,107 @@ +# Phase 16 plan — documentation refresh + +Implementation plan for phase 16 of [the osrlib spec](spec.md): the technical-writer pass over the documentation phases 10–15 updated incrementally. The charter is a five-track review of the published site, the docstrings, and the examples conducted after phase 15 landed (getting-started, the seven guides, the three front-end walkthroughs, the phase 10–15 docstring surface, and the site's information architecture), whose findings this plan triages into work items; the findings are folded in here directly rather than kept as a separate audit artifact — unlike the phase 7 audit, which chartered a 33-module overhaul, this review's output is already work-item-shaped, and a second document would duplicate the plan. The review's calibration matters as much as its findings: every phase 10–15 surface already has a learning-oriented home, every runnable docs example passes under the CI harness, the three TUI transcripts are byte-accurate, the generated references picked up every new module, command, event, and code with zero manual wiring, and the strict build is clean. What needs fixing is a handful of published sentences the later phases falsified, the three pages phase 15 never touched (the FastAPI and LLM-referee walkthroughs, the front door), an information-architecture drift — the authored layer's teaching home is a getting-started page the navigation gives no name — and a vocabulary register that makes the site harder to enter than it needs to be. The milestone: **a developer who has never seen this repository finds, learns, and correctly uses gates, triggers, and quests from the published site alone — and no published sentence contradicts the shipped library.** + +This phase's roadmap entry does not yet exist — the spec's roadmap ends at phase 15 — so this plan PR adds it, pinned verbatim: + +> **Phase 16 — documentation refresh.** The technical-writer pass over the post-phase-15 documentation: the staleness sweep, the authored layer's move from the getting-started tutorial into a guides-level home, the front-end walkthroughs brought into the interpreter era, the front-door and vocabulary pass, and the docstring linkage pass. Milestone: a developer who has never seen the repository finds, learns, and correctly uses gates, triggers, and quests from the published site alone, and no published sentence contradicts the shipped library. + +Four disciplines bound the phase: + +- **Docs adapt to code, and nothing moves but words.** The phase 7 rule verbatim: no symbol renames, no signature changes, no new public symbols, no RNG-path or serialized-name changes, no version bump. The `src/` diff for the entire phase is docstring and comment hunks only. `examples/` code may change — example sources are not the frozen surface, and three of the findings are example rendering defects — but no example change may alter a command sequence or an RNG draw: the golden files stand byte-for-byte, `SCHEMA_VERSION` stays 3 with no new migration, and any golden diff in this phase's changes is a defect by definition. +- **The one-way bridge.** The project's precise vocabulary (gates, triggers, beats, the journal, streams, draws) is load-bearing — it maps one-to-one onto API names — so the fix for the jargon wall is on-ramps, not synonyms. Common, jobs-to-be-done language *locates* a concept (navigation labels, headings, opening sentences: "you want a door that needs a key"); the project term is introduced once, job-first ("osrlib calls this a gate"), and from that sentence on the docs commit to the term. No page maintains a parallel vocabulary, and docstrings stay in full project vocabulary — they are reference, and precision wins there. The B/X domain vocabulary (referee, keyed areas, marching order) is the audience's own and stays, with at most a first-use gloss. +- **The voice gradient.** The docs' authorial register is an asset in the deep material and a cost at the front door, where the reader is also absorbing new vocabulary. The funnel top — README, index, quickstart, guide openings — is written plain, every sentence doing instruction; the register stays rich in guide interiors, walkthroughs, and reference prose, where the reader has bought in. +- **The harness discipline holds through the restructuring.** Every teaching page keeps a complete runnable program under the examples harness, and narrated fragments stay excerpts of their page's program — so the page split below produces two complete programs, not one program and a pile of orphaned fragments. + +## Scope + +In scope: + +- The falsehood and staleness sweep across the guides, getting-started, README, and the walkthroughs — every item named in work items 2–4 +- The split: the authored layer (gates, triggers, quests, narrator steering) moves from `docs/getting-started/building-an-adventure.md` into a new guide, with navigation, cross-links, and both complete programs reworked +- The front-end walkthrough refresh: the FastAPI page gains the interpreter and the served content, the LLM-referee page gains the guidance surface and the authored-narrative story, the TUI page drops the delta-loop idiom — with the small example-code changes those pages need to excerpt +- The front door and vocabulary pass: README, `docs/index.md`, quickstart hand-offs, the concepts table, the heading audit, and a documentation-conventions block in `AGENTS.md` +- The docstring linkage pass over the phase 10–15 modules — orientation staleness, missing cross-references, per-field docstrings where the reference renders bare fields +- Toolchain nits: `dedent_subsections` for snippet excerpts, and the development-history sweep over user-facing files the phase 7 tripwire does not scan (`examples/` READMEs, docs pages) + +Out of scope (deferred to the track that picks each up, or declined with rationale): + +- **Versioned documentation (mike or equivalent)** — the release skill owns the adoption trigger; nothing here changes it +- **A redirects plugin** — declined, for the greenfield reason rather than URL stability: the phase renames one page (`kernel-a-la-carte.md`, work item 4) and moves sections off another, and accommodates neither with a redirect layer. Docs URLs are not among the compatibility contracts `AGENTS.md` names as real (the public API, `schema_version`, the determinism contract), the site's inbound-link surface is effectively zero, and a redirect kept for a consumer nobody can name is exactly the just-in-case scaffolding the discipline forbids. A stale anchor into `building-an-adventure.md` degrades to the page top; a stale link to the old kernel path 404s, and that is accepted +- **A published changelog page** — declined: `CHANGELOG.md` links repo paths the site excludes (`docs/spec.md`), so a snippet-included page fails the strict build's link validation; rewriting the changelog's links per release is maintenance without a demonstrated consumer. `docs/index.md` links the GitHub changelog instead (work item 5) +- **A JTBD rewrite of docstrings** — declined by the one-way-bridge discipline itself: docstrings are reference and keep full project vocabulary +- **The LLM-referee example agent** — not shipped and no longer promised; the page's roadmap sentence is reworded (work item 4), and whether an example agent is worth building is a post-phase decision on its own merits +- **New mechanical gates for prose counts or transcript accuracy** — declined: the two count-drift instances are fixed by removing the counts and the `AGENTS.md` convention forbids new ones; a transcript-diff test would couple the docs build to a TUI run for a hazard the walkthrough's re-capture procedure (work item 4) already manages +- **Engine changes of any kind** — a docs phase; where documentation wants a code shape the code doesn't have, the docs adapt + +## Work items + +### 1. The split — `docs/guides/gates-triggers-quests.md` (new), `docs/getting-started/building-an-adventure.md`, `mkdocs.yml` + +- The new guide, pinned: `docs/guides/gates-triggers-quests.md`, navigation label "Gates, triggers, and quests", placed after "Listeners and flags" — the interpreter is a listener, so the authored layer reads as the shipped application of the pattern the previous guide just taught. These three terms are common game-design vocabulary as well as project vocabulary, so the title needs no translation; the opening frame does the bridge work instead ("You want a door that needs a key, a lever that opens a portcullis across the map, an errand that ends the adventure. osrlib authors all three as data…"). +- What moves, pinned: "Gating a door or a stair", "Wiring the dungeon with triggers" (all three subsections), "Authoring a quest" (all seven subsections, including "Which beat goes where" and "Steering a narrator"), and the three snippet includes those sections carry (`fetch-quest`, `bundled-idol`, `level-guidance`). The root section's authored-layer prose moves too: the `items`/`triggers`/`quests` field descriptions and the ordering rules they carry — both tuples are document order, and the interpreter walks an event's triggers before its quests — land in the new guide's trigger and quest sections, while the root section keeps a one-sentence forward pointer to the guide. What stays in building-an-adventure: the grid and its edges, keyed areas, the dungeon/town/root assembly (its root authoring none of the three moved fields), validation, and a complete program. The stale "Trigger-driven one-time unlocks of that shape arrive in a later release." sentence (line 81) dies in the move rather than as a separate fix — settled in review discussion — and its replacement is a live forward reference to the triggers section it now shares a page with. +- Two complete programs, pinned: building-an-adventure keeps a trimmed program — geometry, a keyed area with its encounter, the root, validation, entry, the goblin spawn beat — and the new guide takes the full gated/triggered/quested program with its journal, source-stamp, and completion assertions. Every narrated fragment on both pages is re-derived as an excerpt of its own page's program. A structural bonus, taken deliberately: the getting-started page's opening fragment currently references the `sentinel` gate defined three sections later; with gates gone from the page, its geometry authors an ungated door and the first fragment finally stands alone. +- The ending, taught by name: the new guide's "The completion rule and the ending" section names `AdventureCompletedEvent` (`session.adventure.completed`) as the event a front end watches for the victory transition — currently stated nowhere in guide prose. +- The `cost_gp=0` question, preempted: one clause where the key and idol templates appear — a bundled item's price is moot because the town shop never stocks it — cross-linking the authoring guide's `items.purchase.not_stocked` treatment. +- Cross-link rewiring, enumerated: `mkdocs.yml` navigation; quickstart's "Where next" (work item 4 rewords it anyway); building-an-adventure's "Where next" points forward to the new guide; `listeners-and-flags.md`'s interpreter section and fetch-quest hand-off links move to the new guide's anchors; `views-and-visibility.md` and `sessions-commands-events.md` gain the outbound links work item 2 specifies; `tui-crawler.md`'s quest-section links retarget. The strict build's anchor validation is the completeness check. + +### 2. The staleness sweep — the guides + +- `sessions-commands-events.md`: the victory paragraph ("Nothing in the library enters it yet — the transition arrives with the authored quest layer") is rewritten to the shipped truth — `CompleteQuest` on a quest authored `concludes_adventure=True` is the one entrance, linking the new guide's ending section — resolving its contradiction with the same page's lifecycle section. "The lifecycle commands" moves after "Session modes and mode gating", whose vocabulary (terminal modes, legal-in-every-mode) it leans on; the intro's page-contract sentence updates to announce the source stamp and lifecycle sections it now walks. The rejections section gains the gate refusal as the one rejection family carrying authored player-facing text (`exploration.door.gate_refused`, `exploration.transition.gate_refused`, the author's `refusal` beat in `params`), linking the new guide. The interpreter-stamp passage gains an inline link to where triggers and quests are authored. +- `determinism-saves-replay.md`, the review's other high-severity page: the schema paragraph corrects "`SCHEMA_VERSION` … is currently `2`" to 3 and describes both migrations (1→2, and 2→3's lossless rewrite of a treasure trap's never-read `trigger="enter"` to `"open"`). A new subsection under replay states the listener rule this page never mentions: `replay_game` builds a session with **no listeners registered**, and that is sufficient because every reaction a listener issued live was an ordinary logged command — re-executing the log rebuilds its every effect. The corollary, scoped precisely: after `load_game`, re-register listeners before executing *new* commands; during a replay, a listener that only observes (accumulating `listener_state`, emitting annotations) may be registered and reproduces its state, but a listener that reacts by *issuing commands* — the interpreter above all — must not be, because the log already carries its reactions and a second issuer would duplicate them and diverge. The spec's own replay bullet currently makes the blanket claim ("Replays reproduce engine state exactly with or without listeners … Re-registering the same listeners during a replay reproduces their state too") that is true only of the observe-only case and false for the interpreter, in tension with the spec's authored-layer section ("a replay, which runs with no listeners"); this phase therefore pins a sentence-level spec amendment scoping that bullet to observe-only listeners and stating the command-issuing exclusion — the phase 12/15 altitude test met exactly, a developer would mispredict from the current text — applied with the implementation PR per the phase 15 precedent. The save-contents list extends to the session-state blocks it omits — the flag store and listener state (the phase 5 extension surface, never listed here) and the trigger fired-marks, journal, and quest state phases 13–15 added — so "does my authored progress survive?" is answerable from the page. The `ReplayVersionError` sentence notes the check runs only when the caller passes the save's recorded `engine_version`. +- `views-and-visibility.md`: one sentence adds the third channel authored words reach a player by — a gate's `refusal` beat riding a rejection — beside events and views, linking the new guide. "What tells a client the journal grew" is promoted out of "The stable difference" to its own section (it is client how-to, not contrast). "Where next" gains `listeners-and-flags.md` (flags' visibility is discussed inline without a link) and the new guide. +- `listeners-and-flags.md`: the fetch-quest listener — the guides' largest code sample with no runnable twin — folds into the page's complete program with its imports, exercised minimally, so the harness covers it. The page's other twin-less fragment, the one-line `register_listener(Interpreter(session))`, closes the same way: the complete program registers the interpreter beside its own listener — legal and inert on an adventure that authors no triggers or quests — so the fragment becomes a true excerpt. The cascade sentence links the new guide's "When something doesn't land". +- `authoring-custom-content.md`: the scope statement and the "Where next" bullet reroute authored *behavior* — gates, triggers, quests — to the new guide, replacing the pre-phase-11 description of building-an-adventure. +- `ruleset-options.md`: the "Where next" sentence routing quests and triggers to listeners-and-flags is rewritten to the post-phase-15 model — session flags and game-owned listeners there, authored triggers and quests in the new guide. + +### 3. The front-end walkthroughs — `docs/front-ends/`, `examples/` + +- The TUI example's rendering changes, pinned as the full list of `examples/` code changes this phase makes: `_run` iterates `result.events` instead of diffing the event log — the delta idiom's stated rationale is false, since the phase 14 `CommandResult` fold already returns everything nested listener-issued commands logged — and prints a rejection's authored `refusal` text when its params carry one, so phase 11's beats stop being silently dropped by the renderer everyone copies. The refusal line's format is pinned: the literal `(refused:` prefix stands, the authored text appended after the code — two clean-run tripwires (`tests/test_example_crawler.py` and the golden generator's marker check) grep for that literal's *absence*, and a reworked prefix would pass green while blinding both. `_status` lists active quests with objective states (rendering `PlayerView.quests`); a `journal` verb prints the journal with clock stamps (rendering `PlayerView.journal`), and `milestone.txt` gains exactly one `journal` line before the closing `status` so the verb has transcript and test coverage — a pure view read like `status`, executing no command and drawing nothing, so the command log and the golden stand unchanged by construction; the verb and the script line land in the same commit, since a script naming a verb that doesn't exist yet trips the generator's unknown-command marker check. `examples/fastapi_crawler/content.py` gains snippet markers around `new_session` and `restore_session`, and `examples/fastapi_crawler/app.py` gains one around the `CreateSession` model and its exactly-one-of validator, which sit outside every existing marker (marker comments only — no behavior change in either file). None of these changes touches a command sequence or a draw: the goldens capture state and logs rather than stdout, and `tests/test_example_crawler.py` assertions move only where they pin output shapes the rendering changes altered, gaining one substring assertion on the `journal` output. +- Transcript re-capture, pinned as procedure: the walkthrough's quoted transcripts are re-captured from the real `--seed 21 --script milestone.txt` run after the rendering changes, never hand-edited — the same discipline that made the current transcripts byte-accurate. +- `tui-crawler.md`: the delta-loop prose (lines 29–33, 57–59) rewrites to the true contract — the result envelope carries the interpreter's reactions, which is why the loop is a plain iteration; the intro's "even a whole quest — is ordinary application code" reframes to the authored-data story its own quest section tells; "a quest listener's reactions" becomes the interpreter; the player-view section teaches `quests` and `journal` with the new excerpts; the source-stamp sentence shows the literal form and notes triggers stamp too; the shrine-excerpt framing stops promising an encounter the excerpt doesn't contain; the reward-economics sentence unpacks "the last award has already fired" so pay-in-coin isn't misread as pay-nothing; and a short passage teaches `SessionMode.terminal` as the loop condition a front end checks — with an honest note that the TUI deliberately keeps its loop open after victory so the closing `status` can be read, and a link to the LLM page's loop sketch where the terminal check is shown. +- `fastapi-pattern.md`, untouched since phase 7 and the review's biggest walkthrough gap: a new section on the served content teaches what the page never says — the server registers `Interpreter` when it creates a session *and again when it restores one*, excerpting the two `content.py` functions; the restore paragraph names the interpreter as the listener it re-registers, making the page's own lesson (listeners are code, saves are data) concrete. The wire-view section adds `journal` and `quests` to the whitelist enumeration and notes the player-visible quest events crossing in `events`, plus the `rejections[].params.refusal` field a web client should render. The `CreateSession` model and its exactly-one-of validator join the excerpts the prose already leans on. "All 44 of them" and every other numeric surface count dies in favor of "every command in the registry". +- `llm-referees.md`: a new "Narrating authored content" section delivers the surface built for this page's audience — `NarrativeBlock.guidance` and `LevelSpec.guidance` as steering text a referee-side narrator reads from the adventure document and never prints verbatim (excerpting `content.py:level-guidance`); the authored beats arriving on player-visible events with `speaker` attribution as text to weave, not paraphrase; registering the library `Interpreter` so an agent refereeing an authored adventure does no trigger or quest bookkeeping; and `Command.source` as the attribution that keeps the agent's own commands distinguishable from authored consequences in the log — this page's own eval story, completed. "Events never carry baked prose" is qualified to what it means: no *engine-baked English*, while authored narrative rides events as structured fields the formatter appends. The authorial-surface section adds the journal and note commands (an agent's durable in-world memory), the quest lifecycle commands with the sharp edge that a hand-issued `CompleteQuest` grants no rewards, and the counts die as above. The "complete example agent is on the roadmap" sentence — a promise no roadmap holds — rewords to fact: the schemas, the referee surface, and the determinism story are the pieces such an agent would consume. +- The development-history sweep: user-facing files outside the phase 7 tripwire's scan (`examples/*/README.md`, docs pages) drop their phase references — the TUI README's "It is the Phase 5 milestone" becomes plain description. The tripwire itself stays `src/`-scoped; the sweep is editorial, verified by grep in the closing pass. + +### 4. The front door and the vocabulary pass — `README.md`, `docs/index.md`, `docs/getting-started/quickstart.md`, `AGENTS.md` + +- README and `docs/index.md`, updated in sync (their positioning is deliberately twinned): one plain sentence advertises the authored surface — adventures carry their own items, gated doors, triggers, and quests; the library ships the interpreter that plays them to a victory ending — and the guide-list sentence names the new guide. The two pages' reference-surface enumerations align (today they drift). `docs/index.md` gains a link to the GitHub changelog. +- The save/load correction, both carriers: README's "Saved games replay from the seed and the command log" and quickstart's "Loading replays the command log against the same seed" are rewritten to the state-restore truth — a save restores from serialized state alone; replay is the separate `replay_game`, and the two agreeing is the determinism guarantee. The quickstart twin blocks are code, not prose, so the twin-equality gate is untouched. +- The concepts table, pinned: a short "What things are called" table on `docs/index.md` — the JTBD row set: quest log → the journal; scripted event → a trigger; locked door needing an item → a gate; the text an event shows → beats on a narrative block; what the player may see → the player view; seedable randomness → named streams and draws; save file → a stamped document; win condition → a concluding quest and `victory` — each row linking where the term is taught. Rows are added sparingly; the table is an index, not a glossary essay. +- Quickstart and index hand-offs: the "Where next" and "Where to start" bullets describing building-an-adventure predate phase 10 ("assembles a small dungeon model by model") and rewrite to name what each page now teaches, with the new guide as the authored-layer destination. +- The heading audit, pinned to its one real offender: "The kernel à la carte" becomes "Using the rules without a session" — navigation label, H1, and file, renamed to `guides/rules-without-a-session.md`, because docs URLs carry no compatibility contract and a filename fossilized under a renamed title is the accommodation the greenfield discipline exists to kill. The term *kernel* is introduced job-first in the opening sentence; the navigation entry and every inbound guide link move with the rename, the strict build catching stragglers. The remaining guide titles survive the audit — they are either API vocabulary developers hold (sessions, commands, events, listeners) or common game-design words (views, determinism, ruleset). Guide openings that lack a job-first frame gain one sentence each, per the one-way bridge; interiors are untouched. +- `AGENTS.md` gains a short documentation-conventions block, pinned to four rules: prose states no numeric surface counts (registries and generated references carry the numbers); vocabulary follows the one-way bridge (job first, term once, then commit — no parallel vocabulary); the voice gradient (front door plain, depth rich); transcripts and captured output are re-captured from real runs, never hand-edited. + +### 5. The docstring linkage pass — `src/`, docstring and comment hunks only + +- Orientation staleness: `crawl/narrative.py`'s module docstring drops "a trigger or a quest as those land" — both landed — and names the three carriers as current; `crawl/adventure.py`'s module docstring adds the authored-content surfaces (`items`, `triggers`, `quests`) and validation's grown reach, with links to the three modules. +- The missing one-way links, closed: `crawl/triggers.py`'s module docstring (and `TriggerSpec`) gains the sentence naming the `Interpreter` as the shipped listener that plays these; `crawl/quests.py`'s module docstring gains the same plus the four lifecycle commands that are quest state's only writers; `crawl/gates.py`'s module docstring links `DoorSpec` and `TransitionSpec`, the only two carriers a `GateSpec` can hang on. +- The selector rule, surfaced where authors read: `GrantItem`, `GrantCoins`, and `AwardXP` each gain one sentence — in an authored consequence or reward, `character_id` takes the party selectors (`@party`, `@first`), expanded by the interpreter before issue; issued directly, it must be a literal member id or the command rejects. +- Field docstrings where the reference renders bare: `NarrativeBlock`'s nine fields (the pure authoring surface — the field list is where an author looks up which beat is which); `DoorEvent.narrative` (matching its already-documented twin on `LocationEnteredEvent`); `QuestView.id`/`.name` and `ObjectiveView.id` for consistency with their sibling fields. +- Envelope completeness: `CommandResult`'s docstring states the phase 14 fold — `events` carries everything nested listener-issued commands logged, in log order — where today only `GameSession.execute` says so. +- Housekeeping while there: the `_record_deaths` link to the filtered private member `_end_on_party_wipe` becomes plain prose (no anchor exists for it). + +### 6. Toolchain — `mkdocs.yml` + +- `pymdownx.snippets` gains `dedent_subsections: true`, so sections excerpted from inside functions stop rendering at source indentation; the affected excerpts (`parse-command`, `idol-shrine-area`, `level-guidance`, the new `content.py` markers) are visually verified in the built site. + +## Sequencing + +1. Work item 1 with work item 6 — the split settles the page structure and anchors everything later edits link to, and the snippet dedent lands before the pages that re-excerpt are proofread. +2. Work item 2 — the guides sweep, against settled structure. +3. Work item 3 — the example code changes, the transcript re-capture, and the three walkthrough refreshes together, so prose and excerpts move in one motion. +4. Work item 4 — the front door last among the content passes, so its links and concepts table point at final anchors. +5. Work item 5 — the docstring pass, independent of page structure, anytime after 1; by convention it lands here. +6. The closing sweep: grep-verified zero numeric surface counts and zero phase references in user-facing files, the full gate on both OSes, and the blind-task list handed to the implementation rubber-duck. + +## Definition of done + +- `uv sync && uv run ruff format --check && uv run ruff check && uv run pyright && uv run pytest && uv run mkdocs build --strict` green on both OSes; the golden files byte-identical and unregenerated; `SCHEMA_VERSION` untouched at 3 with no new migration; the package version untouched; the entire `src/` diff docstring and comment hunks only; the `examples/` diff limited to the changes work item 3 names, with every command sequence and draw unchanged. +- The six falsified claims are gone and stated correctly: the victory entrance, the trigger-unlock "later release" sentence, the schema version, the save/load mechanism (both carriers), the delta-loop rationale, and the two surface counts — and a grep for numeric surface counts in prose returns nothing. +- The new guide is live in the navigation with its complete program under the harness; building-an-adventure stands trimmed with its own program, its first fragment self-contained; every cross-link the split rewires resolves under the strict build. +- The FastAPI page teaches interpreter registration on both paths from real excerpts; the LLM page teaches the guidance surface, the beat-weaving rule, and the completed authorial surface; the TUI page renders quests, the journal, and refusal text through the updated example, its transcripts re-captured byte-accurate. +- The front door advertises the authored layer, the concepts table is live, the kernel guide carries its job-first title at its renamed path, and `AGENTS.md` carries the four documentation conventions. +- The docstring pass holds under the strict build's cross-reference validation: the two stale module orientations rewritten, the one-way links closed in `triggers`/`quests`/`gates`, the selector sentence on the three grant commands, and the named field docstrings rendering in the reference. +- `CHANGELOG.md` `[Unreleased]` gains Changed bullets for the example rendering changes (result-events loop, refusal text, quest status, the `journal` verb) — the docs-only changes carry no bullets. +- Acceptance, pinned: the implementation-phase rubber-duck includes a fresh-eyes, docs-only walkthrough of four blind tasks — author a key-gated door, a trigger, and a concluding quest from the published site alone; build a minimal front end that renders quests, the journal, and a gate's refusal from the walkthroughs alone; answer "what survives a save, and why does replay run with no listeners?" from the determinism guide alone; and, starting from the home page, reach quest authoring in at most two clicks. All four must succeed without reading library source. +- The spec changes exactly twice across the phase: the roadmap entry (this PR) and the replay-listener scoping amendment work item 2 argues (the implementation PR). Every declined item in this plan names its rationale, and `docs/adaptations.md` gains no entries — a docs phase pins engineering, not rules. diff --git a/docs/spec.md b/docs/spec.md index 7a9cfb9..4a906e1 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -389,3 +389,5 @@ Phases 10–15 deliver authored gates, triggers, and quests (see that section). **Phase 14 — triggers and the interpreter.** The trigger spec, authored triggers on the adventure document, and the library-shipped interpreter listener: document-order matching, once-only fired-state, the depth-4 cascade bound with truncation notes, and dropped-consequence recording; `validate_adventure` grows trigger reference checks. Milestone: the lever-opens-portcullis scenario authored as data replays identically with no listeners, and a trigger spawn colliding with an open encounter drops and records its note. **Phase 15 — quests, victory, and the authored example.** The quest spec, the quest lifecycle commands with their state and player-visible events, adventure completion into victory, active quests in the player view, the per-level ambient guidance slot, and quest/objective reference validation; the example TUI crawler registers the interpreter, authors its fetch quest as adventure data, and deletes its hand-rolled listener. Closing deliverable: file the osr-forge issue recording that its overrides schema has no quest surface — quest authoring stays native-project-only until osr-forge grows one in its own repo against this settled schema. Milestone: the crawler's fetch quest — activation, objective completion matched on the idol's catalog id, reward, journal beats, victory — runs end to end as authored data and replays clean. + +**Phase 16 — documentation refresh.** The technical-writer pass over the post-phase-15 documentation: the staleness sweep, the authored layer's move from the getting-started tutorial into a guides-level home, the front-end walkthroughs brought into the interpreter era, the front-door and vocabulary pass, and the docstring linkage pass. Milestone: a developer who has never seen the repository finds, learns, and correctly uses gates, triggers, and quests from the published site alone, and no published sentence contradicts the shipped library.