use crate::agent::ToolCallTrace;
use anyhow::{Context, Result};
use serde::Deserialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Outcome {
Ok,
Failed,
Refused,
}
impl Outcome {
fn of(call: &ToolCallTrace) -> Self {
if call.denied {
Outcome::Refused
} else if call.unknown || call.is_error {
Outcome::Failed
} else {
Outcome::Ok
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Work {
pub calls: u32,
pub failed: u32,
pub refused: u32,
pub verify_like: u32,
pub shell_calls: u32,
pub last: Option<Outcome>,
pub in_flight: u32,
pub denied: u32,
pub run: u64,
}
pub fn next_run() -> u64 {
static RUNS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
RUNS.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}
impl Work {
pub fn of(trace: &[ToolCallTrace]) -> Self {
let mut work = Work::default();
for call in trace {
let outcome = Outcome::of(call);
work.calls += 1;
match outcome {
Outcome::Failed => work.failed += 1,
Outcome::Refused => work.refused += 1,
Outcome::Ok => {
if call.name == "shell" {
work.shell_calls += 1;
}
if looks_like_verification(call) {
work.verify_like += 1;
}
}
}
work.last = Some(outcome);
}
work
}
pub fn with_in_flight(mut self, n: u32) -> Self {
self.in_flight = n;
self
}
pub fn with_denied(mut self, n: u32) -> Self {
self.denied = n;
self
}
pub fn in_run(mut self, run: u64) -> Self {
self.run = run;
self
}
pub fn since(&self, start: Work, bookkeeping: u32, last: Option<Outcome>) -> Option<Span> {
if start.run != self.run {
return None;
}
Some(Span {
calls: self
.calls
.saturating_sub(start.calls)
.saturating_sub(bookkeeping),
failed: self.failed.saturating_sub(start.failed),
refused: self.refused.saturating_sub(start.refused),
verify_like: self.verify_like.saturating_sub(start.verify_like),
shell_calls: self.shell_calls.saturating_sub(start.shell_calls),
last,
in_flight: self.in_flight,
denied: self.denied,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Span {
pub calls: u32,
pub failed: u32,
pub refused: u32,
pub verify_like: u32,
pub shell_calls: u32,
pub last: Option<Outcome>,
pub in_flight: u32,
pub denied: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Finding {
Landed,
Null,
EndedOnFailure,
EndedOnRefusal,
}
pub fn appraise(span: Span) -> Finding {
if span.in_flight > 0 || span.denied > 0 {
return Finding::Landed;
}
if span.calls == 0 {
return Finding::Null;
}
match span.last {
Some(Outcome::Failed) => Finding::EndedOnFailure,
Some(Outcome::Refused) => Finding::EndedOnRefusal,
_ => Finding::Landed,
}
}
impl Finding {
pub fn line(self, step: &str, again: bool) -> Option<String> {
let step = ellipsize(step, 60);
let body = match self {
Finding::Landed => return None,
Finding::Null => format!(
"step \"{step}\" was marked done with no tool calls behind it. \
If it was a decision rather than work, that is what it should say; \
if it was work, it has not been done yet."
),
Finding::EndedOnFailure => format!(
"step \"{step}\" was marked done with its last call still failing, \
and nothing after it succeeded. Check that it landed before moving on."
),
Finding::EndedOnRefusal => format!(
"step \"{step}\" was marked done with its last call refused. \
It was blocked rather than finished — the plan should say which."
),
};
Some(if again {
format!(
"{body} This is the second time this step has come back that way; \
rather than trying it again, say what you need to get past it."
)
} else {
body
})
}
}
fn ellipsize(s: &str, max: usize) -> String {
if s.chars().count() <= max {
return s.to_string();
}
let head: String = s.chars().take(max - 1).collect();
format!("{}…", head.trim_end())
}
fn looks_like_verification(call: &ToolCallTrace) -> bool {
const KEYWORDS: &[&str] = &[
"cargo test",
"pytest",
"npm test",
"npm run test",
"yarn test",
"pnpm test",
"make test",
"go test",
"rspec",
"jest",
];
if call.name != "shell" {
return false;
}
let Some(command) = call.input.get("command").and_then(|v| v.as_str()) else {
return false;
};
let command = command.to_ascii_lowercase();
KEYWORDS.iter().any(|k| command.contains(k))
}
fn reads_as_a_verification_claim(step: &str) -> bool {
const WORDS: &[&str] = &["test", "verify", "confirm", "ensure"];
const PHRASES: &[&str] = &["check that", "make sure"];
let step = step.to_ascii_lowercase();
let tokens: std::collections::HashSet<&str> = step
.split(|c: char| !c.is_alphanumeric())
.filter(|w| !w.is_empty())
.collect();
WORDS.iter().any(|k| tokens.contains(k)) || PHRASES.iter().any(|p| step.contains(p))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EscalationReason {
SpanOutlier,
UnverifiedClaim,
}
#[derive(Debug, Clone, PartialEq)]
pub struct StepEscalation {
pub reason: EscalationReason,
pub step: String,
pub siblings: Vec<String>,
pub calls: u32,
pub sibling_mean_calls: Option<f32>,
pub sibling_count: usize,
}
const SPAN_OUTLIER_RATIO: f32 = 3.0;
const SPAN_OUTLIER_FLOOR: u32 = 6;
const SPAN_OUTLIER_MIN_SIBLINGS: usize = 2;
const ESCALATION_SIBLING_SAMPLE: usize = 5;
pub fn escalation_candidate(
span: Span,
step: &str,
completed: &[(String, u32)],
) -> Option<StepEscalation> {
if completed.len() >= SPAN_OUTLIER_MIN_SIBLINGS {
let mean = completed.iter().map(|(_, n)| *n as f32).sum::<f32>() / completed.len() as f32;
if span.calls as f32 >= mean * SPAN_OUTLIER_RATIO && span.calls >= SPAN_OUTLIER_FLOOR {
return Some(StepEscalation {
reason: EscalationReason::SpanOutlier,
step: step.to_string(),
siblings: completed
.iter()
.rev()
.take(ESCALATION_SIBLING_SAMPLE)
.map(|(s, _)| s.clone())
.collect(),
calls: span.calls,
sibling_mean_calls: Some(mean),
sibling_count: completed.len(),
});
}
}
if reads_as_a_verification_claim(step) && span.shell_calls > 0 && span.verify_like == 0 {
return Some(StepEscalation {
reason: EscalationReason::UnverifiedClaim,
step: step.to_string(),
siblings: Vec::new(),
calls: span.calls,
sibling_mean_calls: None,
sibling_count: 0,
});
}
None
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StepVerdict {
Accept,
RevisePlan,
}
const ESCALATION_PROMPT_TEXT_CHARS: usize = 400;
pub fn escalation_prompt(escalation: &StepEscalation) -> String {
let step_text = ellipsize(&escalation.step, ESCALATION_PROMPT_TEXT_CHARS);
let question = match escalation.reason {
EscalationReason::SpanOutlier => format!(
"This step just finished after {} tool calls. The plan's other completed \
steps averaged {:.1} calls each ({} of them). Does the size of this step \
suggest the plan's decomposition should be revised for the steps still \
ahead, or was this step just harder than the others with nothing wrong \
in how the plan divided the work?",
escalation.calls,
escalation.sibling_mean_calls.unwrap_or(0.0),
escalation.sibling_count,
),
EscalationReason::UnverifiedClaim => format!(
"This step was marked done. Its own wording reads as claiming something \
was tested, verified, or confirmed, but none of its {} tool call(s) \
looked like a check — grade the calls, not the claim. Does this look \
like the step actually verified what it says, or like an unverified \
claim the plan should revisit?",
escalation.calls,
),
};
let siblings = if escalation.siblings.is_empty() {
String::new()
} else {
format!(
"\n\nThe {} most recent of them, for context:\n{}",
escalation.siblings.len(),
escalation
.siblings
.iter()
.map(|s| format!("- {}", ellipsize(s, ESCALATION_PROMPT_TEXT_CHARS)))
.collect::<Vec<_>>()
.join("\n")
)
};
format!(
"You are reviewing one step of your own plan from outside the run that made \
it — you have no tools and cannot act, only judge.\n\n\
The step: \"{}\"\n\
{question}{siblings}\n\n\
Return exactly this JSON and nothing else:\n\
{{\n \"reasoning\": \"one or two sentences\",\n \
\"verdict\": \"accept | revise_plan\"\n}}\n\n\
`accept` is the common, correct answer when the work looks sound; \
`revise_plan` only when there is a real reason to reconsider the \
decomposition.",
step_text,
)
}
pub fn parse_step_verdict(text: &str) -> Result<StepVerdict> {
let start = text
.find('{')
.context("the escalation returned no JSON object")?;
let end = text
.rfind('}')
.context("the escalation returned no JSON object")?;
if end <= start {
anyhow::bail!("the escalation returned no JSON object");
}
#[derive(Deserialize)]
struct Wire {
#[serde(default)]
reasoning: Option<String>,
verdict: String,
}
let wire: Wire = serde_json::from_str(&text[start..=end]).with_context(|| {
let cut = crate::text::char_boundary_at_or_before(text, end.min(start + 400) + 1);
format!("parsing the escalation's verdict: {}", &text[start..cut])
})?;
if let Some(reasoning) = &wire.reasoning {
tracing::debug!(%reasoning, "step escalation reasoning (never shown to the model)");
}
match wire.verdict.as_str() {
"accept" => Ok(StepVerdict::Accept),
"revise_plan" => Ok(StepVerdict::RevisePlan),
other => anyhow::bail!("the escalation returned an unrecognised verdict `{other}`"),
}
}
pub const STEP_ESCALATION_STEM: &str = "A second opinion on your plan:";
pub fn templated_nudge(escalation: &StepEscalation) -> String {
let step = ellipsize(&escalation.step, 60);
let body = match escalation.reason {
EscalationReason::SpanOutlier => format!(
"step \"{step}\" took {} tool call(s) against the plan's other completed \
steps' average of {:.1} — worth checking whether the remaining steps in \
the plan need to be broken down differently, or re-scoped.",
escalation.calls,
escalation.sibling_mean_calls.unwrap_or(0.0),
),
EscalationReason::UnverifiedClaim => format!(
"step \"{step}\" reads as claiming something was tested or verified, but \
nothing in its tool calls looked like a check — worth confirming it \
actually landed before moving on."
),
};
format!("{STEP_ESCALATION_STEM} {body}")
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn call(is_error: bool, denied: bool, unknown: bool) -> ToolCallTrace {
ToolCallTrace {
name: "shell".into(),
input: json!({}),
is_error,
denied,
unknown,
staged: false,
}
}
fn ok() -> ToolCallTrace {
call(false, false, false)
}
fn failed() -> ToolCallTrace {
call(true, false, false)
}
fn denied() -> ToolCallTrace {
call(true, true, false)
}
#[test]
fn a_denial_is_never_counted_as_a_failure() {
let work = Work::of(&[ok(), denied()]);
assert_eq!(work.calls, 2);
assert_eq!(
work.failed, 0,
"the approver doing its job is not a failure"
);
assert_eq!(work.refused, 1);
assert_eq!(work.last, Some(Outcome::Refused));
let refused = appraise(work.since(Work::default(), 0, work.last).unwrap());
assert_eq!(refused, Finding::EndedOnRefusal);
let broke = appraise(
Work::of(&[ok(), failed()])
.since(Work::default(), 0, Some(Outcome::Failed))
.unwrap(),
);
assert_eq!(broke, Finding::EndedOnFailure);
}
#[test]
fn an_unknown_tool_counts_with_the_failures() {
let work = Work::of(&[call(true, false, true)]);
assert_eq!(work.failed, 1);
assert_eq!(work.refused, 0);
}
#[test]
fn a_step_with_nothing_behind_it_is_the_null_step() {
let start = Work::of(&[ok(), ok()]);
let now = start;
assert_eq!(
appraise(now.since(start, 0, now.last).unwrap()),
Finding::Null
);
}
#[test]
fn plan_bookkeeping_does_not_count_as_work() {
let start = Work::default();
let now = Work::of(&[ok(), ok(), ok()]);
assert_eq!(
appraise(now.since(start, 3, now.last).unwrap()),
Finding::Null,
"a step whose whole span is plan revision did nothing"
);
assert_eq!(
appraise(now.since(start, 2, now.last).unwrap()),
Finding::Landed
);
}
#[test]
fn a_bookkeeping_call_landing_last_does_not_mask_a_real_failure() {
let start = Work::default();
let now = Work::of(&[failed(), ok()]);
let span = now.since(start, 1, Some(Outcome::Failed)).unwrap();
assert_eq!(span.calls, 1, "the bookkeeping call is excluded from work");
assert_eq!(
appraise(span),
Finding::EndedOnFailure,
"the caller's `last` overrides the raw trace tail"
);
}
#[test]
fn a_bookkeeping_call_landing_last_does_not_manufacture_a_failure() {
let start = Work::default();
let now = Work::of(&[ok(), failed()]);
let span = now.since(start, 1, Some(Outcome::Ok)).unwrap();
assert_eq!(span.calls, 1);
assert_eq!(
appraise(span),
Finding::Landed,
"a rejected bookkeeping call must not read as the step's own failure"
);
}
#[test]
fn a_denied_sibling_supports_no_finding_either() {
let span = Work::of(&[ok()])
.with_denied(1)
.since(Work::default(), 0, Some(Outcome::Ok))
.unwrap();
assert_eq!(appraise(span), Finding::Landed);
let span = Work::of(&[ok(), denied()])
.with_denied(1)
.since(Work::default(), 0, Some(Outcome::Refused))
.unwrap();
assert_eq!(
appraise(span),
Finding::Landed,
"the denial in the same batch is not necessarily this step's"
);
}
#[test]
fn a_failure_recovered_from_is_the_model_working() {
let start = Work::default();
let now = Work::of(&[failed(), ok()]);
let span = now.since(start, 0, now.last).unwrap();
assert_eq!(span.failed, 1, "the failure is still counted");
assert_eq!(
appraise(span),
Finding::Landed,
"only the last attempt decides; recovery is not a finding"
);
}
#[test]
fn a_sibling_still_running_supports_no_finding() {
let empty = Work::default().with_in_flight(1);
assert_eq!(
appraise(empty.since(Work::default(), 0, empty.last).unwrap()),
Finding::Landed
);
let failing = Work::of(&[failed()]).with_in_flight(1);
assert_eq!(
appraise(failing.since(Work::default(), 0, failing.last).unwrap()),
Finding::Landed
);
}
#[test]
fn a_failure_before_the_step_started_is_not_this_step_s() {
let start = Work::of(&[failed()]);
let now = Work::of(&[failed(), ok(), ok()]);
let span = now.since(start, 0, now.last).unwrap();
assert_eq!(span.failed, 0);
assert_eq!(appraise(span), Finding::Landed);
}
#[test]
fn a_mark_from_another_run_is_unmeasurable_rather_than_empty() {
let first = Work::of(&[ok(), ok(), ok()]).in_run(1);
let second = Work::of(&[ok()]).in_run(2);
assert_eq!(second.since(first, 0, second.last), None);
assert!(Work::of(&[ok(), ok(), ok(), ok()])
.in_run(1)
.since(first, 0, Some(Outcome::Ok))
.is_some());
}
#[test]
fn the_common_path_says_nothing() {
assert_eq!(Finding::Landed.line("read the config", false), None);
}
#[test]
fn a_second_identical_reading_stops_asking_for_a_revision() {
let first = Finding::Null.line("fix the port", false).unwrap();
let second = Finding::Null.line("fix the port", true).unwrap();
assert!(first.contains("fix the port") && !first.contains("second time"));
assert!(second.contains("second time"));
for line in [&first, &second] {
assert!(!line.contains("ask_user") && !line.contains('`'));
}
}
#[test]
fn a_long_step_is_cut_on_a_char_boundary() {
let step = "é".repeat(200);
let line = Finding::Null.line(&step, false).unwrap();
assert!(line.contains('…'));
}
fn shell(command: &str) -> ToolCallTrace {
ToolCallTrace {
name: "shell".into(),
input: json!({"command": command}),
is_error: false,
denied: false,
unknown: false,
staged: false,
}
}
fn span(calls: u32, verify_like: u32) -> Span {
Span {
calls,
failed: 0,
refused: 0,
verify_like,
shell_calls: calls,
last: Some(Outcome::Ok),
in_flight: 0,
denied: 0,
}
}
#[test]
fn a_shell_call_matching_a_test_runner_looks_like_verification() {
for command in [
"cargo test --workspace",
"pytest tests/",
"npm test",
"make test",
"CARGO TEST -p mecha-core",
] {
assert!(
looks_like_verification(&shell(command)),
"{command:?} should have matched"
);
}
}
#[test]
fn an_ordinary_shell_call_does_not_look_like_verification() {
assert!(!looks_like_verification(&shell("cargo build --release")));
assert!(!looks_like_verification(&call(false, false, false)));
}
#[test]
fn work_folds_verify_like_only_for_successful_calls() {
let mut failing_test = shell("cargo test");
failing_test.is_error = true;
let work = Work::of(&[shell("cargo test"), failing_test]);
assert_eq!(work.verify_like, 1);
}
#[test]
fn work_folds_shell_calls_only_for_successful_calls() {
let refused = call(false, true, false);
let failed = call(true, false, false);
let work = Work::of(&[refused, failed]);
assert_eq!(
work.shell_calls, 0,
"neither call actually ran, so shell_calls must stay at zero"
);
let work = Work::of(&[ok()]);
assert_eq!(work.shell_calls, 1);
}
#[test]
fn a_span_far_longer_than_its_siblings_is_a_span_outlier_candidate() {
let completed = vec![
("read the config".to_string(), 2),
("write the file".to_string(), 3),
];
let escalation = escalation_candidate(span(20, 0), "do the big thing", &completed)
.expect("20 calls against a mean of 2.5 should escalate");
assert_eq!(escalation.reason, EscalationReason::SpanOutlier);
assert_eq!(escalation.calls, 20);
assert_eq!(escalation.sibling_mean_calls, Some(2.5));
assert_eq!(escalation.siblings.len(), 2);
}
#[test]
fn a_tiny_plan_never_fires_the_span_outlier_trigger() {
let completed = vec![("read the config".to_string(), 2)];
assert!(escalation_candidate(span(20, 0), "do the big thing", &completed).is_none());
}
#[test]
fn a_step_within_the_floor_never_fires_even_against_a_tiny_mean() {
let completed = vec![("a".to_string(), 1), ("b".to_string(), 1)];
assert!(escalation_candidate(span(3, 0), "a small step", &completed).is_none());
}
#[test]
fn a_step_only_moderately_bigger_than_its_siblings_does_not_escalate() {
let completed = vec![("a".to_string(), 5), ("b".to_string(), 5)];
assert!(escalation_candidate(span(10, 0), "a somewhat bigger step", &completed).is_none());
}
#[test]
fn a_step_that_claims_verification_with_none_in_its_span_escalates() {
let escalation = escalation_candidate(span(3, 0), "test that the API responds", &[])
.expect("a verification claim with no verify-shaped call should escalate");
assert_eq!(escalation.reason, EscalationReason::UnverifiedClaim);
assert!(escalation.siblings.is_empty());
assert_eq!(escalation.sibling_mean_calls, None);
}
#[test]
fn a_step_that_claims_verification_and_has_it_does_not_escalate() {
assert!(escalation_candidate(span(3, 1), "test that the API responds", &[]).is_none());
}
#[test]
fn an_ordinary_step_with_no_claim_and_no_outlier_never_escalates() {
let completed = vec![("a".to_string(), 4), ("b".to_string(), 5)];
assert!(escalation_candidate(span(4, 0), "write the docs", &completed).is_none());
}
#[test]
fn a_word_containing_test_as_a_substring_is_not_a_verification_claim() {
for step in [
"pull the latest changes",
"read the latest config",
"copy the latest bundle",
] {
assert!(
escalation_candidate(span(3, 0), step, &[]).is_none(),
"{step:?} must not read as a verification claim"
);
}
assert!(escalation_candidate(span(3, 0), "test that the API responds", &[]).is_some());
}
#[test]
fn a_claim_with_no_shell_call_at_all_does_not_escalate() {
let no_shell_calls = Span {
calls: 1,
failed: 0,
refused: 0,
verify_like: 0,
shell_calls: 0,
last: Some(Outcome::Ok),
in_flight: 0,
denied: 0,
};
assert!(
escalation_candidate(no_shell_calls, "test that the API responds", &[]).is_none(),
"no shell call ran in this span, so absence of a match proves nothing"
);
}
#[test]
fn only_the_most_recent_siblings_ride_along() {
let completed: Vec<(String, u32)> = (0..20).map(|i| (format!("step {i}"), 2)).collect();
let escalation = escalation_candidate(span(30, 0), "a big step", &completed).unwrap();
assert_eq!(escalation.siblings.len(), ESCALATION_SIBLING_SAMPLE);
assert_eq!(escalation.siblings[0], "step 19");
assert_eq!(escalation.sibling_count, 20);
let prompt = escalation_prompt(&escalation);
assert!(prompt.contains("(20 of them)"));
assert!(prompt.contains(&format!(
"The {ESCALATION_SIBLING_SAMPLE} most recent of them"
)));
}
#[test]
fn a_very_long_step_or_sibling_is_bounded_in_the_prompt() {
let long_step = "x".repeat(5_000);
let long_sibling = "y".repeat(5_000);
let escalation = StepEscalation {
reason: EscalationReason::SpanOutlier,
step: long_step.clone(),
siblings: vec![long_sibling.clone()],
calls: 20,
sibling_mean_calls: Some(2.5),
sibling_count: 1,
};
let prompt = escalation_prompt(&escalation);
assert!(
!prompt.contains(&long_step),
"the full 5,000-char step must not reach the prompt whole"
);
assert!(!prompt.contains(&long_sibling));
assert!(prompt.len() < long_step.len() + long_sibling.len());
}
fn span_outlier_escalation() -> StepEscalation {
StepEscalation {
reason: EscalationReason::SpanOutlier,
step: "do the big thing".into(),
siblings: vec!["read the config".into()],
calls: 20,
sibling_mean_calls: Some(2.5),
sibling_count: 1,
}
}
#[test]
fn the_prompt_asks_for_reasoning_before_the_typed_field() {
let prompt = escalation_prompt(&span_outlier_escalation());
assert!(prompt.find("\"reasoning\"").unwrap() < prompt.find("\"verdict\"").unwrap());
assert!(prompt.contains("do the big thing"));
assert!(prompt.contains("read the config"));
}
#[test]
fn parsing_an_accept_verdict() {
let v = parse_step_verdict(r#"{"reasoning": "looks fine", "verdict": "accept"}"#).unwrap();
assert_eq!(v, StepVerdict::Accept);
}
#[test]
fn parsing_a_revise_plan_verdict_wrapped_in_prose() {
let text = "Here you go:\n```json\n{\"reasoning\": \"too broad\", \"verdict\": \"revise_plan\"}\n```\n";
assert_eq!(parse_step_verdict(text).unwrap(), StepVerdict::RevisePlan);
}
#[test]
fn an_unrecognised_verdict_is_refused() {
assert!(parse_step_verdict(r#"{"reasoning": "x", "verdict": "maybe"}"#).is_err());
}
#[test]
fn an_unparseable_reply_is_an_error() {
assert!(parse_step_verdict("I could not do that.").is_err());
}
#[test]
fn the_nudge_never_contains_the_models_own_reasoning() {
let escalation = span_outlier_escalation();
let nudge = templated_nudge(&escalation);
assert!(nudge.contains("do the big thing"));
assert!(!nudge.contains("looks fine"));
assert!(!nudge.contains("too broad"));
assert_eq!(nudge, templated_nudge(&escalation));
}
#[test]
fn the_unverified_claim_nudge_names_no_siblings() {
let escalation = StepEscalation {
reason: EscalationReason::UnverifiedClaim,
step: "test that the API responds".into(),
siblings: Vec::new(),
calls: 3,
sibling_mean_calls: None,
sibling_count: 0,
};
let nudge = templated_nudge(&escalation);
assert!(nudge.contains("test that the API responds"));
}
#[test]
fn the_nudge_is_recognised_as_the_harness_own_voice() {
assert!(crate::agent::is_harness_voice(&templated_nudge(
&span_outlier_escalation()
)));
let unverified = StepEscalation {
reason: EscalationReason::UnverifiedClaim,
step: "test that the API responds".into(),
siblings: Vec::new(),
calls: 3,
sibling_mean_calls: None,
sibling_count: 0,
};
assert!(crate::agent::is_harness_voice(&templated_nudge(
&unverified
)));
}
}