Replace every occurrence of "Krenn" with "Van Maanen's Star" (or contextual variants like VMS for locale codes, Van Maanen for proper noun contexts). Covers CHANGELOG, briefings, workshop docs, sprint briefings, environmental text examples, templates, ticker content, and architecture docs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
20 KiB
title, description, type, status, workshop, agent, round, created
| title | description | type | status | workshop | agent | round | created |
|---|---|---|---|---|---|---|---|
| Gestalt Round 1: Systems Design Inventory | Systems design inventory of LLM voice pipeline options and trade-offs | workshop | archived | llm-voice-pipeline | gestalt | 1 | 2026-03-07 |
LLM Voice Pipeline Workshop — Round 1: Systems Design Inventory
Author: Gestalt Round: 1 (Inventory — divergent) Date: 2026-03-07
What I Read
docs/architecture/proposed-llm-voice.md— full proposalserver/src/bin/generator_spike.rs— full spike including gen_want, gen_tells, gen_behaviors, apply_relationship_behaviorsserver/src/npc/blueprint.rs— NpcBlueprint, CulturalMarkers, ZoneSpec, CultureProfileserver/src/npc/generate.rs— gen_want, gen_tells, gen_skills, full 10-axis pipelineserver/src/npc/mod.rs— Want, WantKind, TellSystem, Tell, TellTriggercontent/global/rural-zone-spec.ron— current hand-authored quality barcontent/global/culture-van-maanens-star.ron— culture profile with void-oaths and speech registerdecisions/content.md— D-121, D-122, D-123, D-128, D-024, D-029decisions/architecture.md— D-010 (information boundaries)decisions/scope.md— D-114, D-115, D-117, D-119decisions/questions-content.md— Q-012, Q-015 (Q-057 not yet in decisions files — it must be the question this workshop is formally introducing)
The Setup: What the Spike Proved and What It Exposed
Let me be concrete about what the generator actually does to behaviors before I evaluate any option.
The spike has two separate behavior pipelines:
Pipeline 1 — Observable behaviors (blueprint.rs / generator_spike.rs):
Role-specific behaviors drawn from RoleSpec.typical_behaviors. These are the strings the player sees as ambient NPC activity. Current quality bar from rural-zone.ron:
"stops to talk with a passing farmer, eyes still scanning the perimeter" "wipes grease on the thigh of her coveralls between jobs" "holds eye contact through a long pause, waiting for the price to land"
These are already composited observations — character + situation + cultural texture in a single image.
Pipeline 2 — TellSystem (generate.rs / npc/mod.rs):
gen_tells() derives tells from PersonalityTraits + Secret severity. Each Tell has:
trigger: TellTrigger—AlwaysorStressAboveThreshold(simulation state, never player-visible)behavior: String— the observable string the player reads
Current tell strings:
Major secret + stress: "becomes evasive and avoids eye contact"
Cautious + stress: "checks surroundings repeatedly"
Deceptive + stress: "affects exaggerated calm"
Honest + always: "makes direct eye contact"
Social + always: "greets passersby unprompted"
Curious + always: "lingers near unusual activity"
These two pipelines serve fundamentally different functions. This distinction is the most important thing in this document.
The Three Options Through a Systems Design Lens
Option 1: Hand-authored pools (current)
Mechanical evaluation: Doesn't scale and already isn't scaling. The copy team's decision to rename rural-zone-spec.ron → van-maanens-star-rural-zone.ron is a canary. They made the combinatorial explosion explicit: each file is already culture-specific, not a reusable template.
The numbers from the brief (4 roles × ~50 behaviors × N zones × M cultures) understate the problem. With the 10-axis model (D-024), behaviors also need to vary across:
- Secret severity (tells differ when secret is exposed vs. hidden)
- Want intensity (high-intensity Want leaks differently than low)
- Relationship state (behaviors toward specific people require relational context)
Hand-authored pools at full fidelity is O(R × Z × C × Want × Secret × Relationship). That's not thousands of lines — it's hundreds of thousands.
What it preserves well:
- Total mechanical control. Every behavior string is a deliberate authorial decision.
- Tells remain precisely authored micro-behaviors with no ambiguity.
- Zero risk of lore contamination.
Verdict: Correct for Tier 1 authored content. Impossible at the generator scale D-122 requires.
Option 2: Composable primitives (Q-057)
The proposal: Decompose behaviors into role actions + culture modifiers + context tags. Assemble at runtime.
Mechanical evaluation: This is a grammar engine, not a voice system. Let me break down why that matters.
The rural-zone.ron behaviors work because they're already composed — they ARE the composition, rendered as a unified observation:
"stops to talk with a passing farmer, eyes still scanning the perimeter"
The compositional structure inside this is roughly: [social_action][van_maanens_star_directness][vigilance_subtext]. But you can't decompose it without destroying the observation. The thing that makes this line work is that the vigilance is incidental — the character is doing something social while their body does something watchful. That tension is the content. A grammar that assembles "SOCIAL_ACTION + VIGILANCE_TAG" produces:
"talks to a farmer. Watches the perimeter."
That's not a worse version of the same thing. It's a fundamentally different kind of content — behavior report vs. observed character.
The relationship behavior problem is worse. Consider: "talks past Rask without making eye contact." This is:
- A social action with a specific named target
- A relational tell (avoidance encoded as action)
- A character-reads-character moment for the player
Composable primitives would need to represent this as SOCIAL_BYPASS(target=Rask) + TELL(avoidance). But then the assembly problem: how do you compose "talking past someone" + "eye contact avoidance" into natural language without an LLM? You can't. You're back to either hand-authoring the assembly rules for every combination, or you need an LLM anyway to render the composed structure as prose.
Composable primitives is useful as an authoring scaffold, not a runtime engine. If we use it to structure how authors think about behaviors (role action + cultural modifier), that has value. As the player-facing output mechanism, it produces mechanical-feeling text.
What it preserves well:
- Structural correctness — assembled behaviors are always valid
- Scales through combination rather than enumeration
- Explicitly tags mechanical content (good for downstream filtering)
Verdict: The right answer for the authoring schema; the wrong answer for the rendering layer.
Option 3: LLM re-voicing
The proposal: Write culture-neutral semantic base lines. Use a 2B-class model to translate them into character voice using injector clauses (personality, culture, mood).
Mechanical evaluation: This is the most systems-compatible option for the rendering layer — IF we handle the tell separation correctly.
The i18n analogy is the right frame. Base text is en-semantic. Re-voiced text is en-VMS-BOLD. The information is stable; the expression varies.
The proposal correctly identifies that base text serves triple duty: LLM seed, graceful fallback, and LLM-off experience. From a systems standpoint, this is elegant — one authored artifact doing three mechanical jobs simultaneously.
Where it works cleanly:
- Ambient observable behaviors (pipeline 1): "tends crops in the field" → re-voiced to "works the irrigation channels before the morning rotation." The information class is texture, not signal. LLM variance here is fine.
- Dialogue (what NPCs say): Culture and personality naturally belong in re-voicing.
- Relationship framing (non-critical): "nods to a colleague" can be re-voiced without mechanical consequence.
Where it introduces risk:
- Tells (pipeline 2): This is the danger zone. I'll address this separately below.
- Lore contamination: The Van Maanen's Star vocabulary is load-bearing. "Void take it" is not flavor — it's a cultural signal that this NPC belongs to the Settled Reach, not to a generic sci-fi game. A 2B model that hasn't been heavily fine-tuned may default to genre conventions ("damn it", "blast", "stars and garters"). The culture profile has explicit vocabulary (void-oaths, void-adjacent exclamations) that must survive re-voicing intact.
Verdict: Right for the rendering layer. Requires architectural guardrails for mechanical content. The model size ceiling is the critical risk — addressed below.
The Core Mechanical Problem: Tells Are Not Flavor Text
This is where I need to be direct because it's the most important systems design question in this workshop.
Tells are mechanical signals. The player reads them to infer NPC hidden state. They are the physical expression of the information asymmetry mechanic (D-007, D-010 principle 2). The player is not reading for entertainment — they are doing pattern recognition.
Current tell grammar:
| Trigger | Trait | String | What it signals |
|---|---|---|---|
| Always | Honest | "makes direct eye contact" | Baseline positive tell |
| StressAboveThreshold | Major secret | "becomes evasive and avoids eye contact" | Something is wrong |
| StressAboveThreshold | Cautious | "checks surroundings repeatedly" | Anxiety/vigilance |
| StressAboveThreshold | Deceptive | "affects exaggerated calm" | Suppression behavior |
| Always | Curious | "lingers near unusual activity" | Interest tell |
| Always | Bold | "maintains confident posture" | Baseline character texture |
The player who learns this grammar can read an NPC's stress level and trait structure from observation alone. That's the point. That's D-007 pillar 1 expressed as mechanics.
Now apply LLM re-voicing to "becomes evasive and avoids eye contact":
Good re-voicing (semantic preserved): "seems guarded today — won't quite hold your gaze" Acceptable re-voicing: "looks past you when speaking, answers in short clips" Bad re-voicing: "moves through the space with unusual quickness" — WRONG PHENOMENON Bad re-voicing: "seems nervous about the patrol schedule" — ADDED FALSE INFORMATION (crosses D-010 information boundary) Bad re-voicing: "seems different somehow" — LOST SIGNAL (vague, unreadable)
The bad variants aren't stylistically worse — they're mechanically broken. They either corrupt the signal or introduce false state information. A 2B model running local inference with injector clauses cannot be trusted to reliably distinguish "rephrase" from "replace the phenomenon" when processing 10-word behavior strings at scale.
The asymmetric information question from the brief:
"If the same tell reads differently to different players due to phrasing variation, is that a feature or a bug?"
It's a bug, not a feature. Here's why:
The game's core promise (D-005, D-007) is that asymmetric information is a skill — players who observe carefully develop a mental model that gives them better reads on NPC state. Variance in tell phrasing undermines tell literacy. If "becomes evasive" appears as five different phrasings across five NPCs, the player can't learn the pattern.
The "emergent asymmetric information" framing would only apply if different players seeing different phrasings produced different reads — which would be interesting — but the tell-reading skill is about the same player developing pattern recognition across encounters. Phrasing variance across NPCs makes that pattern harder to learn, not more interesting.
Emergent asymmetric information comes from the INFORMATION STRUCTURE (what the player knows vs. what the NPC knows), not from phrasing variance. LLM variance in flavor text is genuinely emergent. LLM variance in mechanical signals is noise.
The Tell Protection Architecture
Here's what I'm proposing we debate in Round 2:
Two-track re-voicing based on content type:
| Content type | Re-voicing mode | Rationale |
|---|---|---|
| Ambient observable behaviors | Free re-voicing | Texture. No mechanical signal. Variance is flavor. |
| Relationship framing (non-tell) | Constrained re-voicing | Preserve who/what. Vary the expression. |
| Relationship tells | Tracked re-voicing | Phenomenon must be preserved. Only vocabulary/register varies. |
| TellSystem behaviors | Locked semantic core | The phenomenon is the mechanical content. Culture-voice the expression, never replace the phenomenon. |
| Dialogue (general) | Free re-voicing | Character voice. Culture and mood. |
| Dialogue (state-revealing) | Tracked re-voicing | Cannot introduce false state. Must preserve the information class. |
"Locked semantic core" implementation sketch:
Each tell in gen_tells() carries a semantic_core alongside the behavior string:
Tell {
trigger: TellTrigger::StressAboveThreshold,
behavior: "becomes evasive and avoids eye contact", // base text / fallback
semantic_core: Some("avoidance_behavior"), // re-voicing constraint
}
The re-voicing prompt for a tell becomes:
"Rephrase in [culture] register. PRESERVE: [semantic_core]. Do not add information. Do not change the observable phenomenon."
This is a constrained task — much easier for a 2B model than free generation. The model is doing localization, not creation. The semantic_core tag is the guardrail.
Who adds semantic_core tags? This is an authoring question for Mellanie to answer. My recommendation: they're authored alongside the behavior strings in gen_tells() at implementation time. It's a small schema addition. The cost is low; the mechanical protection is high.
What Breaks If We Choose the Wrong Option
Wrong choice: Hand-authored pools at scale
Domain break: The generator produces shallow characters. D-122 requires all NPCs generated; D-128 requires culture implicit in location. Without scalable content, Van Maanen's Star-flavor NPCs are indistinguishable from generic sci-fi archetypes. The want/state/tell pipeline is fully functional, but the behavioral surface those tells appear in is thin and repetitive. The player's tell literacy grows but they have nothing interesting to read.
Wrong choice: Composable primitives as runtime output
Domain break: The system produces mechanically correct but experientially hollow characters. The "assembled" quality is noticeable — behaviors read like database queries, not observed humans. Worse: relationship behaviors composed from primitives lose the observational unity that makes them readable. "Colleague + avoidance behavior" reads differently than "walks past Rask without making eye contact." The second one is investigative data. The first one is a tag list rendered as prose.
The deeper break: composable primitives require a composition render step that either uses an LLM (in which case, just use LLM re-voicing with structure) or produces mechanical output (which breaks the experiential quality). You end up needing both systems and gaining the complexity of each.
Wrong choice: LLM re-voicing without tell protection
Domain break: Tell literacy becomes unteachable. Players who invest in learning the observational grammar find that the patterns don't hold — the same Tell trigger appears with different phenomenological signatures across NPCs. The entire mechanic underpinning D-007 pillar 1 degrades from "skill you develop" to "noise you sometimes parse correctly."
Specific failure mode: a Deceptive NPC under stress should read as "suppression" (affects exaggerated calm). If LLM re-voicing outputs "seems guarded and formal" half the time and "stays very still and quiet" the other half — both are valid re-voicings, neither is wrong in isolation — but the player can't learn to recognize "suppression" as a pattern. The information is technically in the text, but the grammar is unstable.
Lore contamination failure: the LLM introduces "thanks be to the Maker" (generic religious flavor) instead of "void take it" (Van Maanen's Star void-oath). Now we have an NPC that sounds like they're from a fantasy game. Culture-vector injectors mitigate this but don't eliminate it at 2B model size.
My Position
The right architecture is LLM re-voicing with tell protection.
More specifically, the hybrid that Q-057/Q-012 have been circling around:
-
Composable primitives as the authoring scaffold — structure how authors specify behaviors (role action, cultural modifier, relationship context). This is the schema, not the rendering layer.
-
LLM re-voicing as the rendering layer — translate semantic base text into culture-voiced output. Free re-voicing for ambient behaviors. Tracked re-voicing for relationship content. Locked semantic core for tells.
-
Tells are excluded from free re-voicing entirely — they are authored once (or generated with gen_tells + semantic_core tags) and culture-voiced with explicit semantic preservation constraints.
-
The NPC tier model maps cleanly to re-voicing intensity:
- D-029's 20% ambient → free re-voicing, no tell constraints needed (few systemic hooks)
- D-029's 50% background → constrained re-voicing, relationship behaviors tracked
- D-029's 30% semi-unique → tracked re-voicing across all content, semantic_core on all tells
- Tier 1 authored (deferred per D-114) → hand-authored, no LLM
This architecture respects D-010 (information boundaries — the LLM cannot introduce false game state), D-121 (culture-primary voice — the injector system does this correctly), D-122 (all NPCs generated at scale — only LLM re-voicing makes this viable), and the five pillars (D-007 — asymmetric information as master mechanic requires tell reliability).
The base text / re-voiced text / graceful fallback model is elegant systems design. Write once, serve three purposes. I support it.
What I Need Answered Before I Can Commit
The player's tell literacy model: cross-NPC grammar or fresh-each-time?
If players are expected to develop a cross-NPC grammar — "I've seen that eye-contact pattern three times, it means deception tell under stress" — then tell strings must be semantically stable not just per-NPC but across all NPCs. The re-voicing of tells must produce consistent phenomenological families. "Evasive" across Van Maanen's Star culture should look like a recognizable family of avoidance behaviors, not random variance.
If tells are fresh-each-time (each observation is context-specific, players interpret them in isolation rather than pattern-matching), then more variance is acceptable, because the player isn't building a grammar — they're reading individual characters.
The 10-axis model (D-024) and the Q-052 analysis of storyteller hint delivery both suggest cross-NPC grammar is the intent. The D-039 wow moments include "The Character's Eye" — the player's character flagging something the player didn't notice, which implies the player is expected to develop pattern recognition that the game can get ahead of.
If the answer is cross-NPC grammar (which I believe it is), then tell re-voicing must produce semantic families, not free variation. "Avoidance" behaviors must all read as avoidance. "Suppression" behaviors must all read as suppression. The LLM prompt for tell re-voicing must specify the semantic family explicitly, and output validation must check phenomenological consistency against the family.
This also determines how we define success criteria for the spike: not just "does the output sound good?" but "can a naive player develop reliable tell-reading from these outputs?"
Summary Table
| Question from brief | Gestalt position |
|---|---|
| Re-voice observable behaviors, dialogue, or both? | Both, with different modes per content type |
| Does re-voicing preserve the tell? | Only with explicit architectural protection (tracked re-voicing + semantic_core) |
| How does determinism work? | Generate once per seed and cache. Tells should be deterministic per NPC (same culture + same trait = same semantic family). |
| Which NPC tiers get which pipeline? | Ambient: free re-voice. Background: constrained. Semi-unique: tracked. Tier 1 (deferred): hand-authored. |
| Is tell variance a feature or a bug? | Bug. Tell literacy requires semantic stability across encounters. |
| What breaks with wrong option? | Hand-authored: shallow content at scale. Composable: hollow output, broken relationship behaviors. LLM without protection: tell grammar unteachable. |
| One question before commit | Is the player's tell literacy model cross-NPC grammar or fresh-each-time? |