The planning package had grown to where a new agent could not tell what was authoritative. Phase 0 execution prompts sat beside the specification; four completed milestone reports sat beside the current one; and upstream AI-DnD's own `plan/` build log and `docs/` project site still described a hosted, scripted, multi-user product with accounts — every screenshot in it showed a Scripts tab and a Sign up button, none of which has existed since M2. `planning/archive/` now holds the history and says so in its own README: `phase0/` for the research that chose AI-DnD, `milestone-reports/` for M1 and M2, `decisions/` for ADR 008, the Phase-0-before-build gate Phase 0 satisfied. `planning/reports/` holds only the current milestone's report, because that is the one M4 planning has to read; it moves to the archive when M4's replaces it. Deleted rather than archived: the Phase 0B execution prompts and the handoff/status/summary documents, the Phase 0A discovery and triage reports, upstream's `plan/` and `docs/` trees, and `frontend/README.md`, which was Vite's template boilerplate. All of it is in Git history, and the two recommendation reports carry every conclusion the deleted research reached. Archived documents are kept verbatim. Paths written inside them point at where those files were when the document was written, which is the point: an evidence record that has been quietly edited is no longer evidence. Active documentation is corrected where it pointed at the removed trees or described removed capability as present. `DEVELOPMENT.md`'s "things M1 did not touch" list had gone stale at M2 and claimed QuickJS scripting was still tested; its test count was 604 against an actual 638. `README.md` loses the upstream CI badge, which reported upstream's pipeline rather than this fork's, and a reference to `backend/app/worldstate/engine.py`, a file that does not exist. `planning/README.md` is rewritten as the documentation index. New: `planning/PROJECT-SOURCES.md` and `planning/project-sources.txt`, the manifest of what belongs in the ChatGPT project's Sources. Source comments referring to the deleted trees are reworded; no behaviour changes. 638 backend tests pass, frontend lints and builds, and a reference scan over all 48 tracked Markdown files reports no unresolved path in active documentation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NCbwH7yLGKsj1rhXXzKSCu
106 lines
4.8 KiB
Markdown
106 lines
4.8 KiB
Markdown
# Phase 0B — Experiment B: Open Dungeon history model
|
|
|
|
Driven live on `127.0.0.1:3111` against Ollama through the "custom"
|
|
OpenAI-compatible provider (`http://127.0.0.1:11434/v1`, `qwen2.5:0.5b`), with
|
|
its own SQLite file.
|
|
|
|
## B1. Schema — no lineage exists
|
|
|
|
`src/lib/db.ts` creates four tables: `chats`, `messages`, `characters`,
|
|
`app_settings`. The message row is:
|
|
|
|
```sql
|
|
CREATE TABLE messages (
|
|
id TEXT PRIMARY KEY,
|
|
chat_id TEXT NOT NULL REFERENCES chats(id) ON DELETE CASCADE,
|
|
role TEXT CHECK (role IN ('user','assistant')),
|
|
content TEXT NOT NULL,
|
|
attachments_json ..., image_request_json ..., generated_image_json ...,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX idx_messages_chat_created ON messages(chat_id, created_at);
|
|
```
|
|
|
|
No `parent_id`, no branch, no take, no depth, no checkpoint table. Order is
|
|
`created_at` (a TEXT timestamp), with ties broken by id.
|
|
|
|
## B2. Retry / Edit / Erase — all destructive, measured
|
|
|
|
```
|
|
BEFORE (5 rows)
|
|
a504cb34 assistant "Oh, Vale, you're just sitting in that rundown ..."
|
|
e349d8b9 user "I pocket a brass key from the ashtray."
|
|
9984692b assistant "You find a worn, faded brass key on the tabletop..."
|
|
bb1ceb3f user "I drive to the address on its tag."
|
|
a6e11115 assistant "Yes, you keep going. There, you can call your ..."
|
|
|
|
EDIT e349d8b9 in place → PATCH /api/chats/{id}/messages/{id}
|
|
original text "brass key from the ashtray" still anywhere in DB? False
|
|
|
|
DELETE a6e11115?after=1 (what BOTH Retry and Erase call)
|
|
rows 5 → 4
|
|
|
|
Scan of every column of every table for the deleted tail
|
|
or the pre-edit text: none
|
|
```
|
|
|
|
- **Edit** is `UPDATE messages SET content = ? WHERE id = ?`. The prior text is
|
|
unrecoverable.
|
|
- **Retry** (`retryLastTurn`, `page.tsx`) deletes the last assistant message and
|
|
everything after it, then regenerates. The discarded attempt is gone.
|
|
- **Erase** (`eraseLastTurn`) deletes the last exchange and the tail.
|
|
- Old future turns are therefore always deleted, never retained.
|
|
|
|
## B3. What depends on the linear model
|
|
|
|
1. **`db.ts`** — 20 exported functions. `addMessage`, `updateMessageContent`,
|
|
`deleteMessageAndAfter` and `getChat` are the history four.
|
|
`getChat` returns a flat `messages` array and must become a lineage query.
|
|
2. **`story-prompt.ts`** — windows by array index:
|
|
`for (let i = messages.length - 1; ...)`, `messages.slice(dropped)`,
|
|
`messages.slice(0, dropped)`. Becomes an ancestry walk.
|
|
3. **The summary watermark is positional — the cost Phase 0A missed.**
|
|
`chats.story_summary_count` records "how many of the chat's oldest messages
|
|
the summary already covers", and `api/story/route.ts` compares
|
|
`evicted.length > stored.coveredCount`, then summarizes
|
|
`evicted.slice(stored.coveredCount)`. "The first N messages" is meaningless on
|
|
a branch. Summaries must be re-anchored to a turn id and made per-lineage.
|
|
4. **`page.tsx` is 3,991 lines** in one component; `api/story/route.ts` is 1,196.
|
|
Retry/erase/edit live there as array slicing (`messages.slice(0, cutFrom)`).
|
|
There is no take stepper, branch panel or tree view to build on.
|
|
5. **No tests.** All of the above would be changed with no regression net.
|
|
|
|
## B4. Invasiveness estimate
|
|
|
|
To reach parent-linked turns, an active head, retained abandoned history, named
|
|
checkpoints and lineage-safe summaries, Open Dungeon needs: a schema migration,
|
|
a rewrite of its persistence read/write path, a rewrite of context assembly, a
|
|
redesign of summarization, and new branch UI — with a test suite written first
|
|
to make any of it safe. This is a from-scratch implementation of the hardest
|
|
part of the specification, not a retrofit.
|
|
|
|
By comparison AI-DnD already has all of it except a non-destructive undo, and
|
|
its reads funnel through one chokepoint (`lineage.Path.clause`).
|
|
|
|
## B5. Worth reusing as reference
|
|
|
|
- The reading experience: serif prose, prose-size control, the composer's
|
|
Do/Say/Story modes.
|
|
- Inline scene images driven by a narrator tool call (`generate_image`), with a
|
|
local FLUX worker on `127.0.0.1:7869` or a user's ComfyUI on `8188`.
|
|
- Character portraits reused as reference images for visual continuity, and fed
|
|
back to the narrator as vision context. This is the most valuable idea here for
|
|
`MEDIA-EXTENSION-CONTRACT.md`.
|
|
- The worker HTTP protocol may be portable even though none of the UI is —
|
|
Open Dungeon is Next.js, AI-DnD is React + FastAPI.
|
|
|
|
## B6. Other findings
|
|
|
|
- The `local` provider hard-codes five Gemma 4 QAT builds
|
|
(`src/lib/text-models.ts`, `LOCAL_TEXT_MODELS`) and `/api/health` reports only
|
|
those as installed. Any other local Ollama model must be reached through the
|
|
"custom" provider. A genre-agnostic app wanting "pick any installed model"
|
|
must lift this.
|
|
- Next.js telemetry is enabled by default and printed its notice on first start.
|
|
- 335 npm packages; `npm audit` reports 6 high, 1 low.
|