use super::fixtures::*;
use super::parent_revival::{CHILD, child_with_mail};
use crate::config::Workflow;
use crate::prompt::dispatch::advance::{AdvanceOutcome, run};
use crate::prompt::resolve::WorkerConfig;
use std::path::Path;
const CHILD_DEPTH: u32 = 1;
fn capped(n: u32) -> WorkerConfig {
WorkerConfig {
workflow: Workflow::parse(
&format!("events: {{}}\nbudgets:\n max_depth: {n}\n"),
Path::new("workflow.yaml"),
)
.unwrap(),
..super::advance::worker_config()
}
}
#[test]
fn depth_equal_to_max_depth_is_allowed_and_the_agent_makes_its_model_call() {
assert_eq!(crate::prompt::budget::derive::depth(CHILD), CHILD_DEPTH);
let ws = child_with_mail();
let adapter = StubAdapter::scripted([StubAdapter::reply_ok(&happy_response_bytes())]);
let (sleeper, git) = (StubSleeper::default(), StubGit::ok());
let (clock, id, tools) = (FixedClock::default(), FixedIdGen, StubToolExecutor::ok());
let deps = valid_deps(&adapter, &sleeper, &git, &clock, &id, &tools, ws.path());
let out = run(ws.path(), CHILD, None, &deps, &mut || {
Ok(capped(CHILD_DEPTH))
})
.unwrap();
assert!(matches!(out, AdvanceOutcome::Terminal), "{out:?}");
assert_eq!(
adapter.observed.borrow().len(),
1,
"an agent at exactly max_depth is not depth-exhausted"
);
assert!(
ws.path()
.join(format!("steps/{CHILD}/001/response.json"))
.exists(),
"the step record of the model call it was allowed to make"
);
assert!(
!git.runs.borrow().iter().any(|(_, args)| {
args.iter()
.any(|a| a.starts_with("refs/lernie/budget-exhausted/"))
}),
"no exhaustion marker at the ceiling"
);
}
#[test]
fn depth_one_over_max_depth_exhausts_before_any_model_call() {
let ws = child_with_mail();
let adapter = unreachable_adapter();
let (sleeper, git) = (StubSleeper::default(), StubGit::ok());
let (clock, id, tools) = (FixedClock::default(), FixedIdGen, StubToolExecutor::ok());
let deps = valid_deps(&adapter, &sleeper, &git, &clock, &id, &tools, ws.path());
let out = run(ws.path(), CHILD, None, &deps, &mut || {
Ok(capped(CHILD_DEPTH - 1))
})
.unwrap();
assert!(matches!(out, AdvanceOutcome::Terminal), "{out:?}");
assert!(
!ws.path().join(format!("steps/{CHILD}")).exists(),
"exhausted at its first boundary — no step was ever recorded"
);
assert!(
git.runs.borrow().iter().any(|(_, args)| args
== &vec![
"update-ref".to_string(),
format!("refs/lernie/budget-exhausted/{CHILD}"),
"HEAD".to_string(),
]),
"the git-native exhaustion marker (§6); got {:?}",
git.runs.borrow()
);
}