Regroup the flat status list into milestones with a 'what this proves' goal, and tag every item with its §2 side (state/text/both), dependencies, and milestone goal. Sequencing calls locked: M3 leads with the playable dungeon (Adjudicator→Combat→Luck) before the comedic roles (Improviser/Banter); streaming deferred until the M2 dialogue experiment proves aliveness. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.2 KiB
Roadmap
Source of truth for scope is CLAUDE.md. This tracks sequencing.
POC — the one question (charter §17)
Does bounded AI dialogue feel alive, or does it feel like a chatbot in a costume?
Test that before building anything else. ~30 minutes of play.
POC scope
- One town, two NPCs with authored knowledge lists
- One dungeon: three fights, one boss
- Two companions: Cadwyn, Brannoc
- Three playable classes: Sellsword, Assassin, Priest
- Luck fully wired: generation, drift, one shrine, one cursed item
- Full proxy, full role split, full canon log
- Authored fallback text for every AI surface
Out of scope (charter §17)
AI-generated story skeletons · multiplayer (never) · mobile · credits/payments/auth · companions leaving · positional combat · more than three classes.
Sequencing
Status: ✅ done · ▶ next · ○ planned. Each item is its own spec → plan → implementation cycle. Each carries its §2 side (state = code owns it · text = AI owns it · both = it is two systems), what it depends on, and the milestone goal it advances.
The milestones are ordered to reach the POC's one question as early as possible, then build the game around a validated answer:
| Milestone | Goal it proves |
|---|---|
| M0 — Foundations ✅ | The contract and the client-side engine exist and are trustworthy. |
| M1 — Prove the server loop ✅ | A real model sits behind /dm/narrate and the pipeline is reusable. |
| M2 — Prove aliveness ◀ here | Does bounded AI dialogue feel alive? — the whole POC question (§17). |
| M3 — Make it a game | The dialogue lives inside real stakes: a playable ~30-min dungeon slice. |
| M4 — POC ship-readiness | Every AI surface degrades with a voice, never an error (§13). |
M0 — Foundations ✅
- ✅ Canon log + origin JSON-Schema contract — api validation, unified 422 envelope (Plan A). §2: state · foundation.
- ✅ Client canon log engine — typed GDScript model (invariants in the model), new-game construction (origin + world + creation → canon log), turn-to-turn maintenance mutators, pure
[FACT]/[MOVE]/[ADJUST_DISPOSITION]tag extractor (Plan B). §2: state · depends on the contract.
M1 — Prove the server loop ✅
- ✅ Narrator / Ollama pipeline (server) — the shared server-side model-call pipeline (Ollama httpx client, role→model routing config, prompt loader + canon-log digest renderer, §10 call logging, single-retry → typed 502) wired through
/dm/narrate. Non-streaming. Both phases landed: (1) pipeline foundation (config/routing/prompts/ollama_client/call_log), (2) Narrator online (authorednarrator.mdbody +narrateservice + gated live smoke). Server returns raw prose; the client extracts tags. The other four roles become thin drop-ins on this pipeline. Live wire proven against qwen3.5; 49 tests. Merged todev(ddc00d4). §2: text · depends on the contract.
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 itsTagExtractorinto 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. The first moment a human sees generated prose in the running game. §2: state (client owns the loop, consumes text) · depends on M1 + the client engine · goal: put the Narrator on screen. - ○ Bounded NPC conversation —
/npc/speakwith persona +knowledge[]+available_moves[]; client validates and applies moves, silently drops the invalid, keeps the prose (§6). Drops onto the proven client loop — adds move-tag validation on top of a display+harvest pipeline that already works. The core experiment: this is the surface §17 is really asking about. §2: both (text = the NPC's voice · state = the validated moves) · depends on the client loop · goal: answer the one question. - ○ Streaming (§14) — server streams Ollama → client; latency reads as the DM is speaking rather than the game is frozen, hiding the ~2s call. Gated on aliveness: landed only after the dialogue experiment above says the prose is worth polishing. Additive to
ollama_client(shaped for it) + an SSE/chunked response + the client stream consumer. §2: text · depends on the client loop · goal: polish, not proof.
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. - ○ Combat — deterministic, seeded per encounter from save state (§10); positionless turn-based; resource-management as the one interesting axis; Luck influences only crit thresholds + borderline status checks (§7). The dungeon: three fights, one boss. Combat flavor text is async, optional Narrator calls (reuses M1). "Ship the boring one" (§10) — mostly state work, low AI risk. §2: state (flavor text = a thin AI layer on top) · depends on the pipeline for flavor · goal: real stakes.
- ○ Luck fully wired — generation exists (Plan B); this adds drift events (sleeping in a real bed, a shrine's blessing, killing something praying), one shrine, one cursed item (e.g. +STR / −LCK). Visible only in prose, never as a number (§7). Gates the Improviser. §2: state · depends on the item + event systems · goal: the signature system, live.
- ○ Improviser —
/dm/improvise: minor off-script events, §7-sandboxed by construction — output passes a validator that can only apply a whitelisted set of state changes (dignity, never progress; structurally incapable of ending a quest). Fires on Luck; hooks Cadwyn. §2: both (text = the event · state = the whitelisted change) · depends on Luck being wired · goal: bad luck as a story, not a fine. - ○ Banter —
/party/banter: companions comment on recent events; low stakes, high charm, aggressively cacheable; reads Brannoc's humiliation log (§9), stacking not overwriting. Prose only, no tags. The cheapest role, landed last. §2: text · depends on the humiliation log (Plan B) + events to comment on · goal: the comedy loop closes.
M4 — POC ship-readiness
- ○ Authored fallback text — full sweep — every AI-dependent surface has authored fallback content (§13), written as writing, not error handling. Each role lands with its own fallback; this is the final pass that guarantees no surface can show the player an error. §2: text · depends on every surface existing · goal: a degraded DM still has a voice.
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).