--- title: "Sprint 26 — Server Briefing" description: "Composable behavior engine, SQLite settings storage, voice pipeline observer integration" type: sprint status: archived sprint: 26 team: "server" --- # Sprint 26: Clean House — Server Tasks **Goal:** Ship the voice pipeline to production by integrating observer, removing v0.1 dead weight, and stabilizing the codebase. **Branch:** `server` **Agents:** Dudley (simulation), Tyre (arch), Hoshe (QA) ## Carry-over from Sprint 25 | # | Title | Status | Notes | |---|-------|--------|-------| | #633 | Composable behavior engine | backlog | Deferred from Sprint 25 — behavior pool explosion problem. No blockers. | ## New Tickets | # | Title | Blocked by | |---|-------|------------| | #627 | SQLite settings storage | — | | #650 | ContentType::Factual — LLM bypass for fact-bearing lines | — | | #652 | Voice pipeline: observer integration | #650 (preferred, not hard block) | | #655 | Remove v0.1 content loading system | — | | #651 | Friendly and RoutineDeviation tells — iterate post-ship | — | Use `tooling/db/ticket show ` for full details. ## Key Decisions - `decisions/content.md` — D-138 (LLM re-voicing pipeline: ContentType::Factual from Spike 2, observer wiring spec), D-121 (voice is culture-driven), D-122 (all NPCs generated) - `decisions/scope.md` — D-117 (zero investigation content in v0.2), D-114 (generator-first) ## Open Questions to Resolve Early - **Q-057: Composable behavior generation** — partially resolved by D-138 (resolves the pipeline question). #633 implementation still needs a concrete behavior primitive format. Resolve the data structure before writing code. Resolve before #633 starts. ## Notes - **#650 ContentType::Factual:** The voice module currently routes all content through the LLM. Spike 2 showed that 2B models corrupt quantitative lines ("14 crates in bay seven" → "fourteen crates are missing") and invert denials. Add `Factual` as a third `ContentType` variant alongside `Dialogue` and `Behavior`. Lines tagged `Factual` skip the LLM entirely and are served as base text. The classification logic lives in `server/src/voice/prompt_builder.rs` (currently builds prompts for all content types). Paula endorsed ContentType::Factual in the Spike 2 session — do not revisit the design decision. - **#652 Voice pipeline observer integration:** The pipeline exists (`server/src/voice/`) but nothing wires into it yet. The observer emits behavior and dialogue events to the client via `server/src/bridge/types.rs` — the voice lookup must intercept those events before they hit the bridge. Integration points: `server/src/voice/lookup.rs` (the query interface), `server/src/perception/observer/mod.rs` (snapshot generation), `server/src/bridge/text_renderer.rs` (current text output path). Fall back to base text on cache miss — never block on LLM. Tell behaviors are passthrough (already routed per #642). Prefer landing #650 first so `Factual` content type is established before observer wiring routes content to it. - **#655 Remove v0.1 content loading system:** Delete `server/src/content/` entirely: `loader.rs`, `types.rs`, `line_pool.rs`, `hot_reload.rs`, `spawn.rs`, `template.rs`, `instantiation.rs`, `entanglement.rs`, `mod.rs`. Also remove: `tooling/content-converter/`, `tooling/validate-content`, `content-ron/` compiled output, `content/_meta/` style guides. Server tests to delete: `server/tests/content_loading.rs`, `server/tests/content_runtime.rs`, `server/tests/content_scaling.rs`, `server/tests/template_instantiation.rs`, `server/tests/template_schema.rs`. **Preserve** `content/global/` (enums, knowledge, culture profiles — still live). Before deleting `server/src/content/types.rs`, audit re-exports: any types still used by other modules must be moved, not dropped. Run `cargo check` after each deletion step, not once at the end. - **#633 Composable behavior engine:** Current hand-authored behavior pools in `server/src/npc/routine.rs` enumerate culture×zone×role combinations, which won't scale to the generator. Goal: introduce a behavior primitive format (role action + culture modifier + context tag) and an assembly function that composes them at NpcBlueprint instantiation time. The `NpcBlueprint` struct in `server/src/npc/blueprint.rs` is the output target. Do not delete existing behavior pools until new assembly produces equivalent output — verify with an eyeball diff on generated behaviors for seed 42. - **#627 SQLite settings storage:** Persistent settings via SQLite on the server side (rusqlite with bundled feature — zero runtime dependency). Architecture: settings live on the SERVER in a SQLite database with per-player tables. The client sends `ChangeSettings` commands over IPC, same as any other player action. The client never touches the database directly. Scope: keybindings, audio volume, display preferences, accessibility options, AI-Enhanced Dialogue toggle. This must land before #646 (client toggle) so the toggle has a real persistence layer instead of a flat config file. Key integration point: the existing subprocess IPC in `server/src/bridge/`. The settings schema should be extensible (key-value with typed columns, not a single JSON blob) so future settings don't require migrations. - **#651 Friendly/RoutineDeviation tells — iterate post-ship:** Spike 2 showed these two tells produce output indistinguishable from neutral on Gemma 2B. Three options: stronger few-shot examples in the prompt, non-speech-act encoding (body language descriptions rather than dialogue register), or treat as a 2B capacity ceiling and defer to a larger model. Start with stronger examples (lowest cost). If no improvement after 3 prompt iterations, document the ceiling and close. This is a low-priority polish ticket — do not block sprint completion on it. ## Dependency Chain ``` #650 (ContentType::Factual) → #652 (observer integration) #627 (SQLite settings) → #646 (client: AI toggle, cross-team) #633 (composable behavior engine) — parallel track, standalone #655 (remove v0.1 content loading) — parallel track, standalone #651 (tells iterate) — parallel track, standalone ``` ## PR Workflow When ready to submit, create a PR with `tea` CLI. **All flags are required** to avoid TTY prompts (see CLAUDE.md "Gitea access" section): ```bash tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): description" --description "body" --base main --head server ```