feat(simulation): voice pipeline integration — Factual bypass, observer wiring, tell iteration (#650 #652 #651)

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>
This commit is contained in:
2026-03-13 09:11:44 +01:00
co-authored by Claude Opus 4.6
parent ce0df2f320
commit 1a4fd578cc
8 changed files with 316 additions and 12 deletions
+35 -6
View File
@@ -22,6 +22,13 @@ pub enum ContentType {
Dialogue,
/// Observable behavior description — re-voiced with "Describe".
Behavior,
/// Fact-bearing line — numbers, causal chains, denials.
///
/// Factual lines bypass the LLM entirely and are served as base text.
/// Spike 2 showed 2B models corrupt quantitative content ("14 crates in
/// bay seven" → "fourteen crates are missing") and invert denials.
/// The simulation is the truth layer — the LLM only handles register.
Factual,
}
/// Result of prompt building, including which injections fired.
@@ -57,6 +64,15 @@ OUTPUT CONSTRAINTS:\n\
/// "make sentences shorter" instruction causes destructive compression that
/// strips facts. Long-Angry instead preserves the full claim and focuses
/// intensity on one sentence.
///
/// ## Iteration history for Friendly and RoutineDeviation
///
/// Spike 2 showed these two tells produce output indistinguishable from neutral
/// on Gemma 2B. Tracked against a 3-iteration budget (#651):
///
/// - **Iteration 1** (Sprint 26): Replaced abstract instructions with concrete
/// surface-pattern examples. Friendly: closing aside pattern. RoutineDeviation:
/// self-correction/echo pattern. Both more imitable for a 2B model.
fn tell_injector(category: TellCategory) -> &'static str {
match category {
TellCategory::Nervous => {
@@ -70,9 +86,12 @@ fn tell_injector(category: TellCategory) -> &'static str {
Do not say they seem angry."
}
TellCategory::Friendly => {
"TONE: Add one small extra detail or aside that wasn't strictly necessary. \
Example: \"Inspection's tomorrow — should be fine, though.\" \
Do not add compliments or forced warmth."
// Iteration 1: replaced abstract "add detail" with a concrete closing-aside
// pattern. 2B models need a recognisable syntactic target, not a description
// of intent. "actually" / "so that's something" are learnable short tokens.
"TONE: End with a brief unprompted aside — a phrase the person didn't need to say. \
Example: \"Parts are in, so that's something.\" or \"Shift's been quiet, actually.\" \
Do not use praise or warm adjectives. One short beat after the main point."
}
TellCategory::Guarded => {
"TONE: Use formal, precise words. Answer exactly what was asked, nothing extra. \
@@ -80,9 +99,12 @@ fn tell_injector(category: TellCategory) -> &'static str {
Do not say they seem guarded."
}
TellCategory::RoutineDeviation => {
"TONE: Start the sentence on topic, then add a brief unfinished thought about something else. \
Example: \"Pressure's fine. I was going to — anyway, it's logged.\" \
Do not explain what they were thinking about."
// Iteration 1: replaced the two-step interrupted-thought pattern (too complex
// for 2B) with a simpler self-correction / word-echo pattern. The model only
// needs to repeat a key word or phrase — one concrete surface action.
"TONE: Repeat a key word or phrase, as if catching mid-thought. \
Example: \"Logged it. Got it logged, yeah.\" or \"Pressure's — pressure's holding.\" \
Do not explain. Just the echo."
}
}
}
@@ -269,6 +291,11 @@ pub fn build_prompt(
"Describe the following action as a third-person observer. \
Preserve all individual actions in sequence. Do not extract conclusions"
}
ContentType::Factual => {
// Factual lines must be intercepted before reaching build_prompt.
// If this branch is hit, the caller has a bug.
unreachable!("ContentType::Factual must not reach build_prompt — bypass at worker")
}
};
parts.push(String::new());
parts.push(format!("TASK: {}.", task_verb));
@@ -370,6 +397,7 @@ mod tests {
TellCategory::Friendly,
],
}],
behavior_modifiers: vec![],
}
}
@@ -399,6 +427,7 @@ mod tests {
voice_persona: None,
voice_examples: vec![],
occasional_injections: vec![],
behavior_modifiers: vec![],
}
}