#650 ContentType::Factual — Lines with numbers/denials/causal chains bypass LLM, served as base text
#652 Voice pipeline observer integration — Enrichment systems rewrite dialogue with voiced text before snapshot assembly; graceful degradation on cache miss
#651 Tell iteration — Stronger few-shot examples for Friendly/RoutineDeviation tells
#627 SQLite settings storage — Per-player persistent settings via rusqlite (bundled), protocol v20 with settings commands over IPC
Delete the hand-authored YAML content pipeline (server/src/content/) superseded
by the v0.2 generator-first approach (D-122, D-128). Runtime ECS types that were
co-located with content loading have been extracted to dedicated simulation modules:
- simulation/triangle.rs: TriangleState, TriangleCrisisEventQueue, tick/resolve systems
- simulation/line_pool.rs: LinePoolIndex, AccessTier, TrustTier, Mood, LinePoolIndexResource
- simulation/knowledge_grant.rs: KnowledgeGrant, Prerequisites
Monologue systems (trigger_monologue, trigger_recognition_monologue,
trigger_event_monologue) now use hardcoded fallback lines only; the
ContentStoreResource branch and select_pool_line function are removed.
Deleted: content/{loader,types,line_pool,hot_reload,spawn,instantiation,entanglement,mod}.rs
Deleted: tests/{content_loading,content_runtime,content_scaling,template_instantiation,template_schema}.rs
Deleted: bin/line_preview.rs (v0.1 tool)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ContentType::Factual bypasses LLM for fact-bearing lines (numbers,
denials). Observer enrichment systems rewrite dialogue/conversation
text with voiced versions before snapshot assembly. Friendly and
RoutineDeviation tells get concrete surface-pattern examples.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-player settings via rusqlite (bundled, zero runtime dep). Server
owns the settings DB; client sends ChangeSettings commands over IPC.
Extensible key-value with typed columns (String/Int/Float/Bool).
Protocol bumped to v20 with settings_response in ObserverSnapshot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three review tracks: Hoshe (code quality), Tyre (architecture), Gestalt (systems design foundations).
Hoshe (Code Quality): REQUEST_CHANGES
#
File
Severity
Issue
1
settings/mod.rs:173-185
warning
Delete returns success: true with error: Some(...) when key not found — broken contract. Either return success: false when not found, or treat as silent no-op (no error set).
2
npc/blueprint.rs:~167
suggestion
Doc on BehaviorModifier claims "at most one modifier per category per NPC" but assemble_behaviors does no dedup. Drop the doc claim — occasional repetition is acceptable and avoids an uncanny "every NPC is unique" pattern. The true fix for variety is richer modifier pools in the content, not engine-level dedup.
3
voice/integration.rs:173-175
suggestion
Conversation content_index hash collision rationale is undocumented. The cache key includes entity_id so collisions require same culture + same speaker + same text — document why this is safe rather than leaving as a TODO.
4
bridge/types.rs:87
warning
Version comment says "Current: 19", should be 20. Third time this pattern has recurred — consider a compile-time assertion or doc-gen.
5
settings/store.rs:~50
suggestion
open_in_memory() skips PRAGMA foreign_keys = ON — tests may miss FK violations.
6
settings/store.rs:161-188
suggestion
columns_to_value / columns_to_value_offset differ only by index offset — consolidate into single helper.
7
simulation/line_pool.rs:~358
suggestion
Empty active_situations silently returns zero results — add tracing for content debugging.
8
simulation/knowledge_grant.rs:~16
suggestion
#[serde(untagged)] silently drops entity_ref if both fields present — consider validation at load.
Tyre (Architecture): REQUEST_CHANGES
#
File
Severity
Issue
1
bridge/types.rs:87
warning
ObserverSnapshot.version doc says "Current: 19" — should be 20. (Same as Hoshe #4.)
2
simulation/monologue.rs
suggestion
trigger_monologue is a no-op stub still registered in the schedule — remove from registration or annotate lifecycle.
3
simulation/monologue.rs
suggestion
trigger_event_monologue doc still references removed COOLDOWN_TICKS constant.
Gestalt (Foundations): APPROVE
All three new systems graded SOLID. Clean separation, graceful degradation at boundaries, determinism preserved (BTreeMap usage, seed-driven RNG). Ready to build on.
#
File
Severity
Issue
1
npc/blueprint.rs
suggestion
Silent fallback when modifier_hint doesn't match any category — log for content debugging.
2
npc/blueprint.rs
suggestion
OffDuty context has no test coverage in filter tests.
3
settings/mod.rs
suggestion
"Last response wins" batching — multi-change same-tick acks are incomplete. Worth a comment.
4
settings/store.rs
suggestion
Unknown value_type silently converts to String instead of logging.
5
voice/integration.rs
suggestion
Re-voicing heavily occluded text may produce incoherent output — accepted risk, worth a comment.
6
voice/worker.rs
suggestion
Dead child process causes repeated warnings without recovery — consider respawn or loop break.
7
voice/prompt_builder.rs
suggestion
Multiple INJECT blocks indistinguishable to model if multiple injections fire same prompt.
Verdict: CHANGES REQUESTED
Must-fix (2 items):
Protocol version comment — bridge/types.rs:87 says "Current: 19", should be 20.
Delete response contract — settings/mod.rs returns success: true with error: Some(...) when key not found. Pick one: success: false, or silent no-op.
Everything else is suggestion-level and can be addressed in follow-up tickets.
## Review: server → main (type: code + foundations)
Three review tracks: Hoshe (code quality), Tyre (architecture), Gestalt (systems design foundations).
---
### Hoshe (Code Quality): REQUEST_CHANGES
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | `settings/mod.rs:173-185` | **warning** | `Delete` returns `success: true` with `error: Some(...)` when key not found — broken contract. Either return `success: false` when not found, or treat as silent no-op (no error set). |
| 2 | `npc/blueprint.rs:~167` | suggestion | Doc on `BehaviorModifier` claims "at most one modifier per category per NPC" but `assemble_behaviors` does no dedup. Drop the doc claim — occasional repetition is acceptable and avoids an uncanny "every NPC is unique" pattern. The true fix for variety is richer modifier pools in the content, not engine-level dedup. |
| 3 | `voice/integration.rs:173-175` | suggestion | Conversation content_index hash collision rationale is undocumented. The cache key includes entity_id so collisions require same culture + same speaker + same text — document why this is safe rather than leaving as a TODO. |
| 4 | `bridge/types.rs:87` | **warning** | Version comment says "Current: 19", should be 20. Third time this pattern has recurred — consider a compile-time assertion or doc-gen. |
| 5 | `settings/store.rs:~50` | suggestion | `open_in_memory()` skips `PRAGMA foreign_keys = ON` — tests may miss FK violations. |
| 6 | `settings/store.rs:161-188` | suggestion | `columns_to_value` / `columns_to_value_offset` differ only by index offset — consolidate into single helper. |
| 7 | `simulation/line_pool.rs:~358` | suggestion | Empty `active_situations` silently returns zero results — add tracing for content debugging. |
| 8 | `simulation/knowledge_grant.rs:~16` | suggestion | `#[serde(untagged)]` silently drops `entity_ref` if both fields present — consider validation at load. |
### Tyre (Architecture): REQUEST_CHANGES
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | `bridge/types.rs:87` | **warning** | `ObserverSnapshot.version` doc says "Current: 19" — should be 20. (Same as Hoshe #4.) |
| 2 | `simulation/monologue.rs` | suggestion | `trigger_monologue` is a no-op stub still registered in the schedule — remove from registration or annotate lifecycle. |
| 3 | `simulation/monologue.rs` | suggestion | `trigger_event_monologue` doc still references removed `COOLDOWN_TICKS` constant. |
### Gestalt (Foundations): APPROVE
All three new systems graded **SOLID**. Clean separation, graceful degradation at boundaries, determinism preserved (BTreeMap usage, seed-driven RNG). Ready to build on.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | `npc/blueprint.rs` | suggestion | Silent fallback when `modifier_hint` doesn't match any category — log for content debugging. |
| 2 | `npc/blueprint.rs` | suggestion | `OffDuty` context has no test coverage in filter tests. |
| 3 | `settings/mod.rs` | suggestion | "Last response wins" batching — multi-change same-tick acks are incomplete. Worth a comment. |
| 4 | `settings/store.rs` | suggestion | Unknown `value_type` silently converts to String instead of logging. |
| 5 | `voice/integration.rs` | suggestion | Re-voicing heavily occluded text may produce incoherent output — accepted risk, worth a comment. |
| 6 | `voice/worker.rs` | suggestion | Dead child process causes repeated warnings without recovery — consider respawn or loop break. |
| 7 | `voice/prompt_builder.rs` | suggestion | Multiple INJECT blocks indistinguishable to model if multiple injections fire same prompt. |
---
### Verdict: **CHANGES REQUESTED**
**Must-fix (2 items):**
1. **Protocol version comment** — `bridge/types.rs:87` says "Current: 19", should be 20.
2. **Delete response contract** — `settings/mod.rs` returns `success: true` with `error: Some(...)` when key not found. Pick one: `success: false`, or silent no-op.
Everything else is suggestion-level and can be addressed in follow-up tickets.
- line_pool.rs: add trace! when active_situations is empty (Layer 2
will silently filter all lines — important for content debugging)
- knowledge_grant.rs: document serde(untagged) ambiguity hazard; add
KnowledgeGrant::validate() for load-time field validation
- monologue.rs: annotate trigger_monologue as schedule ordering anchor;
fix stale "periodic trigger cooldown tracking" doc reference in
trigger_event_monologue (COOLDOWN_TICKS removed in #655)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Must-fix: protocol version comment now references PROTOCOL_VERSION
(no hardcoded number), settings delete is idempotent no-op.
Suggestions addressed: BehaviorModifier dedup claim dropped, hash
collision safety documented, FK pragma in test store, columns_to_value
consolidated, modifier_hint mismatch logging, OffDuty test coverage,
batching tradeoff documented, unknown value_type warning, occluded
text risk documented, dead child respawn in voice worker, INJECT
block ambiguity documented.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-review: server → main (fix commits b37583d, 51414b0)
Hoshe (Code Quality): APPROVE
All 16 items from the initial review verified resolved. One low-severity note: KnowledgeGrant::validate() doc implies it catches the serde(untagged) ambiguity, but it only validates empty strings. Not blocking — just a doc tightening opportunity.
Tyre (Architecture): APPROVE
All 3 items resolved. Version comment now references PROTOCOL_VERSION via intra-doc link — eliminates the recurring doc-drift class entirely. Monologue stub properly documented as schedule ordering anchor with clear removal criteria. Voice worker respawn logic is architecturally sound with correct one-shot semantics.
Verdict: APPROVED
Ready to merge.
## Re-review: server → main (fix commits `b37583d`, `51414b0`)
### Hoshe (Code Quality): APPROVE
All 16 items from the initial review verified resolved. One low-severity note: `KnowledgeGrant::validate()` doc implies it catches the serde(untagged) ambiguity, but it only validates empty strings. Not blocking — just a doc tightening opportunity.
### Tyre (Architecture): APPROVE
All 3 items resolved. Version comment now references `PROTOCOL_VERSION` via intra-doc link — eliminates the recurring doc-drift class entirely. Monologue stub properly documented as schedule ordering anchor with clear removal criteria. Voice worker respawn logic is architecturally sound with correct one-shot semantics.
### Verdict: **APPROVED**
Ready to merge.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Sprint 26 (Clean House) server deliverables:
Stats
cargo check --testscleanTest plan
cargo check --testspasses/pr-reviewDelete the hand-authored YAML content pipeline (server/src/content/) superseded by the v0.2 generator-first approach (D-122, D-128). Runtime ECS types that were co-located with content loading have been extracted to dedicated simulation modules: - simulation/triangle.rs: TriangleState, TriangleCrisisEventQueue, tick/resolve systems - simulation/line_pool.rs: LinePoolIndex, AccessTier, TrustTier, Mood, LinePoolIndexResource - simulation/knowledge_grant.rs: KnowledgeGrant, Prerequisites Monologue systems (trigger_monologue, trigger_recognition_monologue, trigger_event_monologue) now use hardcoded fallback lines only; the ContentStoreResource branch and select_pool_line function are removed. Deleted: content/{loader,types,line_pool,hot_reload,spawn,instantiation,entanglement,mod}.rs Deleted: tests/{content_loading,content_runtime,content_scaling,template_instantiation,template_schema}.rs Deleted: bin/line_preview.rs (v0.1 tool) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Review: server → main (type: code + foundations)
Three review tracks: Hoshe (code quality), Tyre (architecture), Gestalt (systems design foundations).
Hoshe (Code Quality): REQUEST_CHANGES
settings/mod.rs:173-185Deletereturnssuccess: truewitherror: Some(...)when key not found — broken contract. Either returnsuccess: falsewhen not found, or treat as silent no-op (no error set).npc/blueprint.rs:~167BehaviorModifierclaims "at most one modifier per category per NPC" butassemble_behaviorsdoes no dedup. Drop the doc claim — occasional repetition is acceptable and avoids an uncanny "every NPC is unique" pattern. The true fix for variety is richer modifier pools in the content, not engine-level dedup.voice/integration.rs:173-175bridge/types.rs:87settings/store.rs:~50open_in_memory()skipsPRAGMA foreign_keys = ON— tests may miss FK violations.settings/store.rs:161-188columns_to_value/columns_to_value_offsetdiffer only by index offset — consolidate into single helper.simulation/line_pool.rs:~358active_situationssilently returns zero results — add tracing for content debugging.simulation/knowledge_grant.rs:~16#[serde(untagged)]silently dropsentity_refif both fields present — consider validation at load.Tyre (Architecture): REQUEST_CHANGES
bridge/types.rs:87ObserverSnapshot.versiondoc says "Current: 19" — should be 20. (Same as Hoshe #4.)simulation/monologue.rstrigger_monologueis a no-op stub still registered in the schedule — remove from registration or annotate lifecycle.simulation/monologue.rstrigger_event_monologuedoc still references removedCOOLDOWN_TICKSconstant.Gestalt (Foundations): APPROVE
All three new systems graded SOLID. Clean separation, graceful degradation at boundaries, determinism preserved (BTreeMap usage, seed-driven RNG). Ready to build on.
npc/blueprint.rsmodifier_hintdoesn't match any category — log for content debugging.npc/blueprint.rsOffDutycontext has no test coverage in filter tests.settings/mod.rssettings/store.rsvalue_typesilently converts to String instead of logging.voice/integration.rsvoice/worker.rsvoice/prompt_builder.rsVerdict: CHANGES REQUESTED
Must-fix (2 items):
bridge/types.rs:87says "Current: 19", should be 20.settings/mod.rsreturnssuccess: truewitherror: Some(...)when key not found. Pick one:success: false, or silent no-op.Everything else is suggestion-level and can be addressed in follow-up tickets.
Re-review: server → main (fix commits
b37583d,51414b0)Hoshe (Code Quality): APPROVE
All 16 items from the initial review verified resolved. One low-severity note:
KnowledgeGrant::validate()doc implies it catches the serde(untagged) ambiguity, but it only validates empty strings. Not blocking — just a doc tightening opportunity.Tyre (Architecture): APPROVE
All 3 items resolved. Version comment now references
PROTOCOL_VERSIONvia intra-doc link — eliminates the recurring doc-drift class entirely. Monologue stub properly documented as schedule ordering anchor with clear removal criteria. Voice worker respawn logic is architecturally sound with correct one-shot semantics.Verdict: APPROVED
Ready to merge.
Pull request closed