use super::{model, world};
use crate::boundary::Action;
use crate::boundary::reply::Reply;
use crate::cli_outbound::Cli;
use crate::opslog::{self, DETACHED_EXIT};
use crate::start::Prepared;
use crate::test_support::engine;
use std::path::Path;
use tempfile::tempdir;
fn signed(deps: crate::boundary::dispatch::Deps) -> crate::boundary::dispatch::Deps {
crate::boundary::dispatch::Deps {
world: crate::test_support::signed(&deps.world),
..deps
}
}
const AGENT: &str = "20260101T000000Z-c1";
fn fake_litany(dir: &Path) -> Cli {
let path = dir.join("litany");
crate::test_support::write_exec(&path, "#!/bin/sh\nexit 0\n");
Cli::new(path)
}
fn prepared(w: &super::World) -> Prepared {
Prepared {
workspace: crate::naming::leaf(&w.ws_cobalt),
binding: Some(w.ws_cobalt.clone()),
goal: "prefill".into(),
origin: crate::opslog::Origin::Conversation,
lineage: None,
}
}
#[test]
fn the_engines_dispatch_is_the_one_chokepoint_a_posted_act_reaches() {
let bin = tempdir().unwrap();
let w = world();
let (_c, m) = model(&w);
let litany = fake_litany(bin.path());
let deps = m.boundary_deps(&litany, &Cli::new("/no/bl"));
let action = Action::Scan {
workspace: crate::naming::leaf(&(w.ws_cobalt.clone())),
};
let Reply::Outcome(outcome) = engine::act(&m, &deps, "TS", &action).unwrap() else {
panic!("a verb answers an outcome");
};
assert!(outcome.ok());
let ops = opslog::tail(&w.roots.yog_state, 4);
assert_eq!(ops.last().map(|e| e.ts.clone()), Some("TS".to_owned()));
}
#[test]
fn the_retarget_exit_spawns_the_bound_litany_verb() {
let bin = tempdir().unwrap();
let w = world();
let (_c, m) = model(&w);
let litany = fake_litany(bin.path());
let deps = m.boundary_deps(&litany, &Cli::new("/no/bl"));
let action = Action::Retarget {
workspace: crate::naming::leaf(&(w.ws_cobalt.clone())),
agent: AGENT.into(),
};
let Reply::Outcome(outcome) = engine::act(&m, &deps, "TR", &action).unwrap() else {
panic!("a verb answers an outcome");
};
assert!(outcome.ok());
let ops = opslog::tail(&w.roots.yog_state, 4);
let last = ops.last().expect("the verb is on the trail");
assert_eq!(
last.argv[1..],
[
"retarget".to_owned(),
w.ws_cobalt.display().to_string(),
AGENT.to_owned()
]
);
assert_eq!(last.cwd, w.ws_cobalt.display().to_string());
}
#[test]
fn the_prompt_door_launches_detached_and_mints_off_the_seat_s_own_seed() {
let bin = tempdir().unwrap();
let w = world();
let (_c, m) = model(&w);
let litany = fake_litany(bin.path());
let deps = signed(m.boundary_deps(&litany, &Cli::new("/no/bl")));
let action = Action::Prompt {
prepared: prepared(&w),
goal: "go".into(),
seed: Some(7),
};
let Reply::Started { conversation } = engine::act(&m, &deps, "T1", &action).unwrap() else {
panic!("the prompt door answers the minted name");
};
assert!(
!conversation.is_empty(),
"the minted conversation name rides back"
);
let ops = opslog::tail(&w.roots.yog_state, 4);
assert_eq!(
ops.last().map(|e| e.exit),
Some(DETACHED_EXIT),
"the handoff's §4.2 sentinel row"
);
let dead = signed(m.boundary_deps(&Cli::new("/no/such/litany"), &Cli::new("/no/bl")));
let err = engine::act(&m, &dead, "T2", &action).unwrap_err();
assert!(!err.is_empty());
}
#[test]
fn a_seedless_prompt_mints_off_the_stamp() {
let bin = tempdir().unwrap();
let w = world();
let (_c, m) = model(&w);
let litany = fake_litany(bin.path());
let deps = signed(m.boundary_deps(&litany, &Cli::new("/no/bl")));
let action = Action::Prompt {
prepared: prepared(&w),
goal: "go".into(),
seed: None,
};
let Reply::Started { conversation } = engine::act(&m, &deps, "T9", &action).unwrap() else {
panic!("the prompt door answers the minted name");
};
assert!(!conversation.is_empty(), "a name was minted regardless");
}
#[test]
fn an_attempt_dispatches_the_ordinary_fork_and_logs_its_whole_argv() {
let bin = tempdir().unwrap();
let w = world();
let (_c, m) = model(&w);
let litany = fake_litany(bin.path());
let deps = m.boundary_deps(&litany, &Cli::new("/no/bl"));
let action = Action::Fork {
workspace: crate::naming::leaf(&(w.ws_cobalt.clone())),
parent: AGENT.into(),
attempt: crate::fork::Attempt {
from: "aaaa1111".into(),
role: "worker".into(),
skills: vec!["bash".into()],
},
goal: "try it the other way".into(),
};
let Reply::Outcome(outcome) = engine::act(&m, &deps, "TS", &action).unwrap() else {
panic!("a verb answers an outcome");
};
assert!(outcome.ok());
let argv = opslog::tail(&w.roots.yog_state, 4)
.last()
.map(|e| e.argv.clone())
.unwrap_or_default();
assert!(argv.contains(&"dispatch".to_owned()), "{argv:?}");
assert!(argv.contains(&"worker".to_owned()), "{argv:?}");
assert!(argv.contains(&AGENT.to_owned()), "{argv:?}");
assert!(argv.contains(&"--from".to_owned()), "{argv:?}");
assert!(argv.contains(&"aaaa1111".to_owned()), "{argv:?}");
assert!(
argv.contains(&"try it the other way".to_owned()),
"{argv:?}"
);
let pin = argv.iter().find(|a| a.starts_with("skills/bash/SKILL.md="));
let pin = pin.expect("the skill rides as a pin");
assert!(pin.contains("world/litany/skills/bash/SKILL.md"), "{pin}");
}