feat: implement processTurn function to handle turn processing and world state updates

refactor: remove legacy types.ts file and update frontend to use new contracts

feat: add applyActions function to manage action application and world state mutation

chore: remove empty .gitkeep file from sqlite data directory

refactor: update frontend App component to align with new API contracts and improve UX

docs: revise project.md to reflect updated architecture and system requirements

docs: update thoughts.md with current status, architecture decisions, and remaining checks
This commit is contained in:
2026-04-24 01:04:17 -04:00
parent 2f6af46c79
commit 998635f542
21 changed files with 1472 additions and 1740 deletions

View File

@@ -1,97 +1,54 @@
# thoughts.md
## Current Status
- Scaffold complete: `charactergarden/` folder structure created per spec section 9
- Core contracts defined in `app/src/types.ts`: Entity, Action, Verb, ValidationResult, StateChange, GameEvent, Turn, Belief, Fact, Affordance, Summary
- `docker-compose.yml` created; ollama service gated behind `--profile llm` (not required for MVP)
- `.env` / `.env.example` / `.gitignore` in place
- Container-first runtime files added: app/frontend Dockerfiles and `.dockerignore`s
- **Truth Engine implemented** in `app/src/truthEngine.ts` — pure function, no I/O, no LLM
- `validate(actions, worldState)` → ValidationResult
- `applyChanges(worldState, changes)` → new WorldState (immutable)
- All 8 verbs handled with explicit rejection reasons
- `move` now supports a built-in offscene room convention via `createOffsceneRoom()`
- `latentEntities.ts` can promote plausible personal items from belief to fact when the actor has carrying context
- `db.ts` added with SQLite schema + persistence helpers for `entities`, `events`, `turns`, `beliefs`, and `summaries`
- Minimal Fastify server + app pipeline added with seeded world state and fallback parser
- Minimal Vite React inspector added for visual boot testing and state inspection
## Current Status (clean-break)
- Backend is running the new contract-native API shape:
- `GET /api/state` -> `{ worldState, turns }`
- `POST /api/turn` -> `{ rawText, actions, validation, worldState }`
- Runtime blocker is resolved:
- old SQLite schema conflict (`turns.raw_text`) was fixed by wiping old DB state
- stale legacy files removed from backend source tree:
- `app/src/types.ts`
- `app/src/latentEntities.ts`
- `app/src/llmAdapter.ts`
- Door/key MVP smoke checks pass:
- `open door` before key -> `locked_requires_key`
- `take key` -> success
- `open door` after key -> success
## Current Architecture Decisions
- App: Node.js + Fastify + TypeScript
- Frontend: React + Vite + TypeScript
- Database: better-sqlite3 (synchronous, no ORM)
- Ollama is optional; system must work without it (per section 14)
- `Event` type renamed `GameEvent` in code to avoid collision with the DOM `Event` global
- Latent personal items are gated by facts-derived affordances, not accepted directly from beliefs
- The offscene room is represented as a normal room entity with id `offscene`
- App and frontend should be run and validated through Docker Compose rather than host-installed Node
## Architecture Now
- Core contracts in `app/src/contracts/`:
- `action.ts`
- `validation.ts`
- `turn.ts`
- `entity.ts`
- `world.ts`
- Deterministic truth engine:
- `app/src/truthEngine.ts` with `validateActions(actions, worldState)`
- Ordered turn pipeline:
- `app/src/turns/processTurn.ts` parse -> validate -> apply -> persist
- World mutation:
- `app/src/world/applyActions.ts`
- Persistence:
- `app/src/db.ts` with tables `turns`, `actions`, `validation_results`, `entities`, `world_states`
- App seed domain:
- `app/src/app.ts` door/key world (`room_start`, `room_exit`, `player`, `door_1`, `key_1`)
## MVP Readiness (2026-04-23)
- Estimated completion: ~90%
- Completed against spec:
- Turn pipeline implemented end-to-end (input -> parse -> validate -> apply -> events -> narration)
- Truth Engine is authoritative for state mutation
- SQLite persistence for entities/events/turns/beliefs/summaries
- Dockerized app + frontend stack, with optional Ollama profile
- Minimal inspector UI for state/events/turns
- MVP world bounded to 2 rooms and <=3 characters
- Remaining to call MVP done:
- Run one clean boot smoke pass from current branch and record expected outputs in this file
- Add a short "MVP acceptance checklist" section and mark each contract as pass/fail
- Tighten fallback parser behavior for known starter prompts and ensure no regression on latent-item turns
## New Endpoint
- Added `POST /api/reset` in `app/src/index.ts`
- App-level reset implementation in `app/src/app.ts`
- DB wipe support in `app/src/db.ts`
- Verified reset behavior:
- returns `{ worldState, turns }`
- `turns` is empty after reset
- `player` and `key_1` return to `room_start`
## MVP Acceptance Checklist
- PASS: Core contracts implemented (Entity, Action, ValidationResult, StateChange, GameEvent)
- PASS: Truth Engine is sole authority for state mutation
- PASS: Invalid actions produce explicit rejection reasons
- PASS: Turn flow wired end-to-end in app service
- PASS: SQLite tables for entities/events/turns/beliefs/summaries
- PASS: Dockerized app + frontend, no host Node dependency required
- PASS: MVP scope bounds respected (2 rooms, <=3 characters, limited verb set)
- PASS: Frontend inspector can submit turns and inspect state/events
- PASS: Latent personal-item flow works in runtime (`pull out my phone` => promoted + accepted)
- PASS: Parser now fails gracefully with explicit rephrase guidance for unknown/underspecified input
## Frontend Migration Notes
- `frontend/src/App.tsx` migrated to consume new backend contracts.
- Removed dependencies on old fields (`narration`, `events`, `beliefs`, `summaries`, `parser_feedback`).
- Turn submit flow now refreshes snapshot via `GET /api/state` after `POST /api/turn`.
- Reset call now sends JSON body/content-type to satisfy Fastify media-type validation.
## Next Steps
1. Execute and capture a final Docker boot smoke check (`/health`, `/api/state`, `/api/turn` happy path + latent-item turn)
2. Add explicit MVP acceptance checklist results here (contracts, scope limits, runtime constraints)
3. Do a small parser-hardening pass for prompt coverage, then freeze MVP scope
4. Defer non-MVP work (container-entity plausibility, richer narration, full LLM adapter)
## Open Questions
- None currently blocking MVP implementation.
## Resolved Decisions (2026-04-23)
- Room/location model: keep `location` as an entity attribute that points to another entity id. Rooms remain normal entities (`type: room`) and inventory uses `inventory:<actor_id>`.
- MVP initial world: lock to 2 rooms (`garden`, `shed`) and 2 characters (`player`, `groundskeeper`), plus static scene objects (`gate`, `bench`) and built-in `offscene` room.
- Latent personal-item plausibility: use actor attributes as the MVP source of truth (`clothed`, `pocket_count`, `has_bag`, `searched_empty`).
- Container/worn-item entities: defer to post-MVP. Add this as a planned extension, not a current gate for plausibility.
## Follow-up Implications
1. Keep truth rules keyed to entity `attributes.location` and avoid introducing a separate room-graph subsystem yet.
2. Keep fallback parser and truth engine behavior tuned to the locked MVP world and verb set.
3. Add a backlog item for container-aware plausibility (`worn`, `container`, nested inventory checks) after MVP boot/test milestone.
## Turn Contract (Higher Stack)
- End-user turn response should always include:
- `narration` (what happened)
- `parser_feedback` when intent is unclear or underspecified
- accepted/rejected action detail for debugger/inspector views
- UX rule: when `parser_feedback` is present, UI should explicitly surface it and encourage rephrasing.
## LLM Prompting Contract (In-Environment)
- Added prompt builder in `app/src/llmAdapter.ts` (`buildActionExtractionPrompt`) to enforce world-grounded extraction.
- Prompt constraints:
- only allowed verbs
- only known entity ids from current world snapshot
- strict JSON output shape (`actions`, optional `parser_feedback`)
- no freeform world mutation outside truth-engine validation
## Session Notes
- 2026-04-23: Project started. Scaffold, type contracts, .gitignore, and .env.example created.
- 2026-04-23: Truth Engine implemented. Pure validation with per-verb handlers and immutable applyChanges helper.
- 2026-04-23: Added facts/affordances + latent entity resolver for improv-style personal items, plus offscene room support.
- 2026-04-23: Added SQLite schema module. Host `npm install` is blocked by `better-sqlite3` on Windows Node 25, so runtime validation should happen inside Docker on an LTS Node image instead.
- 2026-04-23: Added minimal backend/frontend boot slice so the project can be tested visually through Docker.
- 2026-04-23: Runtime smoke check passed with live services (`/health` ok, state returned, `look around` accepted, `pull out my phone` accepted with zero rejections).
- 2026-04-23: Fallback parser hardened to return human-readable guidance on unclear input (e.g., unknown intent, missing take target, missing move destination) and suggest concrete rephrasing examples.
## Remaining Checks
1. Frontend build pass completed in container (`docker compose exec frontend npm run build`).
2. Validate inspector UX manually against the door/key flow.
3. Expand parser coverage only within current clean MVP domain.