From 57acfb75d96dc07a7bd5cb4e891cd33a4ecceba5 Mon Sep 17 00:00:00 2001 From: Phillip Tarrant Date: Fri, 10 Jul 2026 15:44:15 -0500 Subject: [PATCH] docs(roadmap): considering-state done; shelve streaming for the POC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flip considering-state to done+merged+live-confirmed. Strike the streaming item — the considering-state reframes the wait and is tested/live; real streaming's transport rework + mid-stream failure surface isn't worth it for the POC. Streaming spec retained as a record (banner SHELVED). Includes the human's folded-in further-down roadmap ideas. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/roadmap.md | 12 ++++++++++-- .../2026-07-10-narrator-streaming-design.md | 17 +++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 03612f3..d284c8f 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -49,8 +49,8 @@ The milestones are ordered to reach the POC's one question as early as possible, ### M2 — Prove aliveness ◀ *(the POC's one question)* - ✅ **Client HTTP loop** — client posts its canon log to `/dm/narrate`, displays the prose, harvests `[FACT]` via its `TagExtractor` into its own log, and shows the degraded-DM authored fallback (§13) on any non-200. First end-to-end vertical slice: **state → HTTP → model → prose → screen → fact-harvest.** Pure `DmService` core behind an injectable transport seam; throwaway harness scene for the first on-screen prose. **Live-proven** against qwen3.5 through Docker (grounded scene prose, no numbers per §7). 67/67 client tests; merged to `dev` (`b949cd2`). Surfaced + fixed two Docker-dev gaps in M1 (prompts not packaged, no container→host-Ollama route) — M1's live proof had been venv-on-host only. *§2: state (client owns the loop, consumes text) · goal: put the Narrator on screen.* - ✅ **Bounded NPC conversation** — `/npc/speak` with server-owned persona + `knowledge[]` (spoilers stay off the client) and client-computed `available_moves[]`; the client validates each emitted move against live state, applies the valid, silently drops the invalid, and always keeps the prose (§6). Server role is a thin drop-in on the M1 pipeline (`npc.run` mirrors `narrate.py`); the client added a pure `MoveValidator` (membership is the whole test) + a `MoveApplier` that writes town-NPC disposition to `GameState.npc_dispositions` (not the party log), plus `NpcContent.available_moves` as the single legality home. Free text goes straight to the NPC prompt (no Adjudicator needed — the moves are the NPC's). **Live-proven** against qwen3.5: Fenn answered in-voice, grounded strictly in his authored knowledge, no Luck leak (§7), with `reveal`/`offer_quest` moves landing. The live smoke also caught two real tag-format drifts a unit test can't — paren-less zero-arg moves and a dropped `MOVE:` prefix leaking into prose — both fixed by making `TagExtractor` tolerant/scrub-safe (backward-compatible; narrator path unaffected). Built on `feature/npc-conversation`; awaiting the human's `--no-ff` merge to `dev` (§18). *§2: both (text = the NPC's voice · state = the validated moves) · goal: answer the one question.* -- ▶ **Considering-state + transport timeout** — while a model call is in flight the client shows a rotating in-character "the Master considers…" indicator (authored content, §13 spirit — even *loading* is content) instead of a frozen surface, and the `HttpTransport` request timeout is set so a hung call gives way to the authored fallback instead of spinning forever. Meets §14's anti-freeze *goal* by **reframing** the wait, on the *proven* non-streaming loop, with essentially no new failure surface. *§2: text/UI · depends on the client loop · goal: the wait is framed (in-character) and bounded (never hangs).* -- ○ **Streaming** (§14) — **PARKED** (`specs/2026-07-10-narrator-streaming-design.md`). Server streams Ollama → client to genuinely *hide* the ~2s call. Deferred behind the considering-state: it is the POC's largest transport rework (client `HTTPRequest` → poll-based `HTTPClient`) and adds mid-stream error/tag-boundary failure surface — too much risk for "polish, not proof" while the aliveness question is already answered. **Revisit** only if playtesting shows the wait hurts immersion (long responses or a slow prod model). Conscious deviation from §14's "stream everything," recorded here per §18. *§2: text · goal: polish, not proof.* +- ✅ **Considering-state + transport timeout** — while a model call is in flight the client rotates authored in-character "the Master considers…" lines (§13 spirit — even *loading* is content; `ConsideringPhrases` + `ConsideringIndicator`, 3.0s cadence) instead of a frozen surface, and `HttpTransport` sets a request timeout (35s, rejects ≤0) so a hung call degrades to the authored fallback instead of spinning forever. Meets §14's anti-freeze *goal* by **reframing** the wait, on the *proven* non-streaming loop, with no new failure surface. **Human-confirmed live** including the degrade path (API down → fallback). Merged to `dev` (`099714d`); 110/110 client tests. *§2: text/UI · goal: the wait is framed (in-character) and bounded (never hangs).* +- ~~**Streaming** (§14)~~ — **SHELVED for the POC.** Real token streaming would genuinely *hide* the ~2s call, but it is the POC's largest transport rework (client `HTTPRequest` → poll-based `HTTPClient`) and adds mid-stream error/tag-boundary failure surface not worth the risk. The considering-state above reframes the wait instead and is tested and live. Design kept as a record (`specs/2026-07-10-narrator-streaming-design.md`, banner SHELVED); revive only if playtest proves the wait genuinely hurts. Conscious deviation from §14's "stream everything," recorded per §18. ### M3 — Make it a game *(the playable ~30-min slice — dungeon first, per the sequencing call)* - ○ **Adjudicator** — `/dm/adjudicate`: free text → a legal action or an in-world rejection, **strict JSON** (§12), small/fast model, the one-retry-with-error-appended path. Unlocks the hybrid input model (§15) the playable slice needs — the "what do you do?" boundary. *§2: both (text = the in-world reason · state = the chosen action) · depends on the pipeline · goal: free-text world actions.* @@ -64,3 +64,11 @@ The milestones are ordered to reach the POC's one question as early as possible, ### Deferred beyond POC Replicate provider (prod) · auth · metering · credits/payments (§4) — retrofit onto the pipeline later, the game doesn't notice. AI-generated story skeletons (v2 — the seeded story is authored for now). + +#### NPC & relationship depth (v2) + +Three ideas mined from [NarrativeEngine-P](https://github.com/Sagesheep/NarrativeEngine-P) (MIT) — design borrowed, not code. All three are **§2: state** (code owns them; the AI only voices from what code decides), so they strengthen the §2 boundary rather than loosen it. None is in POC scope (§17); they fold into the NPC role (§6) and canon log (§11) once bounded dialogue is proven alive. Sequence them after M3's Adjudicator, since they enrich the same conversation surface. + +- ○ **Directional dispositions** — split the single per-pair disposition into two directed fields (A→B and B→A), so liking is asymmetric. Unrequited regard, undisclosed betrayal (player still trusts the captain who already sold them out), and the Cadwyn↔Brannoc mutual-but-differently-flavored dislike (§9) all become expressible. Player→NPC gates dialogue *tone*; NPC→player gates *offered moves* (§6 `available_moves`) — two arrows, two levers. Extends `party[]` in the canon log (§11) and `npc_dispositions` on the client; keep the −100..100 range, just double the field. *§2: state · depends on the disposition model existing (M2, done) · goal: relationships that aren't symmetric.* +- ○ **Witness tracking** — every logged event carries a `witnesses: [...]` list; a fact enters an NPC's `knowledge[]` (§6) only if they witnessed it or a witness told them. This is the missing **input-side rule** for the knowledge list — CLAUDE.md §6 says the list is "the entire content the NPC has to draw on" but never says how a fact gets *in*. Structurally prevents the blacksmith spoiling a twist he never saw, gives shady acts real "were you seen?" stakes without a stealth system, and turns rumor spread into a code operation (witness meets NPC → code copies the fact, optionally degraded) rather than AI invention. Adds a field to `recent_events[]`/`established_facts[]` (§11) and a propagation rule on character encounters. *§2: state · depends on the canon log event model (M0, done) + knowledge lists (§6) · goal: NPCs know only what they could plausibly know.* +- ○ **Personality Hexagon persona** — a richer NPC persona schema: six axes (Drive, Diligence, Boldness, Warmth, Empathy, Composure) supplied to the NPC prompt (§6) as structured voice-shaping input, replacing free-form persona blurbs. Server-owned (like `knowledge[]`), so it never ships to the client. Purely additive to the §6 prompt contract — it steers *how* an NPC speaks, not *what* it may do (the move vocabulary is unchanged). *§2: state (the schema) feeding text (the voice) · depends on the NPC role (M2, done) · goal: consistent, distinct NPC voices from data, not prose.* diff --git a/docs/superpowers/specs/2026-07-10-narrator-streaming-design.md b/docs/superpowers/specs/2026-07-10-narrator-streaming-design.md index 3a8bfc3..d5c6ac3 100644 --- a/docs/superpowers/specs/2026-07-10-narrator-streaming-design.md +++ b/docs/superpowers/specs/2026-07-10-narrator-streaming-design.md @@ -1,13 +1,14 @@ # Narrator streaming (M2) — design -> **STATUS: PARKED (2026-07-10).** Deferred in favour of a lightweight -> considering-state (see `2026-07-10-considering-state-design.md`), which meets -> §14's anti-freeze *goal* by reframing the wait in-character rather than hiding -> it — for a fraction of the risk (this piece is the POC's largest transport -> rework and adds mid-stream error/tag-boundary failure surface that a -> "polish, not proof" feature shouldn't). Revisit only if playtesting shows the -> wait genuinely hurts immersion (long Narrator responses or a slow prod model). -> This design stays ready for that moment. +> **STATUS: SHELVED for the POC (2026-07-10).** The considering-state +> (`2026-07-10-considering-state-design.md`) shipped and is live-confirmed; it +> meets §14's anti-freeze *goal* by reframing the wait in-character rather than +> hiding it, for a fraction of the risk. Real streaming is the POC's largest +> transport rework (client `HTTPRequest` → poll-based `HTTPClient`) and adds +> mid-stream error/tag-boundary failure surface judged not worth it. The roadmap +> item is struck. This design is retained only as a record — revive it solely if +> playtesting proves the wait genuinely hurts immersion (long Narrator responses +> or a slow prod model). Not planned work. Date: 2026-07-10 Milestone: **M2 — prove aliveness** (roadmap). The third M2 item; **polish, not