use super::super::{has_pending_result, interpret_pending, run_flush};
use super::{Fx, returned_child, returned_child_ep, workflow};
use crate::prompt::inbox::Epitaph;
use crate::prompt::{ChildDispatchRequest, Error, SystemClock, child_dispatch};
use crate::template::GitRunner;
use crate::workspace::{agent_worktree, fixture};
#[test]
fn a_worker_result_delivers_by_default_transfer_plus_transcript() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p1";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let child = returned_child(&ws, parent, "worker", "do it", ("out.txt", "result\n"), &fx);
let wt = agent_worktree(&ws, parent);
interpret_pending(&ws, parent, &wt, &workflow("events: {}\n"), &fx.deps()).unwrap();
assert_eq!(
std::fs::read_to_string(wt.join("out.txt")).unwrap(),
"result\n"
);
let delivered = wt.join(format!("messages/001-{child}.md"));
assert!(delivered.exists(), "result message delivered to transcript");
assert!(!has_pending_result(&ws, parent).unwrap(), "inbox consumed");
}
#[test]
fn a_compactor_result_lands_the_compaction_merge_and_consumes_the_message() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p2";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let child = returned_child(
&ws,
parent,
"compactor",
"compact",
("summary/001.md", "sum\n"),
&fx,
);
let wt = agent_worktree(&ws, parent);
interpret_pending(&ws, parent, &wt, &workflow("events: {}\n"), &fx.deps()).unwrap();
assert_eq!(
std::fs::read_to_string(wt.join("summary/001.md")).unwrap(),
"sum\n"
);
let subj = fx
.git
.run_capture(&wt, &["log", "-1", "--format=%s"])
.unwrap();
assert!(
subj.contains(&format!("compaction merge [{child}]")),
"{subj}"
);
assert!(
!has_pending_result(&ws, parent).unwrap(),
"trigger consumed"
);
assert!(!wt.join(format!("messages/001-{child}.md")).exists());
}
#[test]
fn a_died_compactor_return_lands_no_merge_and_delivers_the_epitaph() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p9";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let child = returned_child_ep(
&ws,
parent,
"compactor",
"compact",
("summary/001.md", "partial\n"),
Epitaph::Died,
&fx,
);
let wt = agent_worktree(&ws, parent);
interpret_pending(&ws, parent, &wt, &workflow("events: {}\n"), &fx.deps()).unwrap();
let log = fx.git.run_capture(&wt, &["log", "--format=%s"]).unwrap();
assert!(!log.contains("compaction merge"), "{log}");
assert!(!wt.join("summary/001.md").exists(), "no compactor tree");
let delivered = wt.join(format!("messages/001-{child}.md"));
let body = std::fs::read_to_string(&delivered).unwrap();
assert!(body.contains("epitaph: died"), "{body}");
assert!(!has_pending_result(&ws, parent).unwrap(), "inbox consumed");
}
#[test]
fn a_stopped_compactor_return_lands_no_merge_under_an_explicit_binding() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-pa";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let work = ("summary/001.md", "partial\n");
let child = returned_child_ep(
&ws,
parent,
"compactor",
"compact",
work,
Epitaph::Stopped,
&fx,
);
let wt = agent_worktree(&ws, parent);
let wf = workflow("events:\n compactor_return:\n - compaction_merge\n");
interpret_pending(&ws, parent, &wt, &wf, &fx.deps()).unwrap();
let log = fx.git.run_capture(&wt, &["log", "--format=%s"]).unwrap();
assert!(!log.contains("compaction merge"), "{log}");
assert!(wt.join(format!("messages/001-{child}.md")).exists());
}
#[test]
fn an_explicit_worker_return_binding_is_honored() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p3";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let child = returned_child(&ws, parent, "worker", "do it", ("out.txt", "x\n"), &fx);
let wt = agent_worktree(&ws, parent);
let wf = workflow("events:\n worker_return:\n - deliver_result\n");
interpret_pending(&ws, parent, &wt, &wf, &fx.deps()).unwrap();
assert!(wt.join(format!("messages/001-{child}.md")).exists());
}
#[test]
fn an_unsupported_child_result_action_is_declined_loudly() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p4";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
returned_child(&ws, parent, "worker", "do it", ("out.txt", "x\n"), &fx);
let wt = agent_worktree(&ws, parent);
let wf = workflow("events:\n worker_return:\n - notify_ui\n");
let err = interpret_pending(&ws, parent, &wt, &wf, &fx.deps()).unwrap_err();
assert!(matches!(err, Error::ActionUnsupported { .. }), "{err:?}");
}
#[test]
fn has_pending_result_is_false_without_a_result_message() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p5";
fixture::spawn_root(&ws, parent);
crate::prompt::inbox::deposit(&ws, parent, "user", "hi", &SystemClock).unwrap();
assert!(!has_pending_result(&ws, parent).unwrap());
}
#[test]
fn interpret_pending_skips_a_steering_deposit() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p8";
let wt = fixture::spawn_root(&ws, parent);
crate::prompt::inbox::deposit(&ws, parent, "user", "hi", &SystemClock).unwrap();
let fx = Fx::new();
let wf = workflow("events: {}\n");
interpret_pending(&ws, parent, &wt, &wf, &fx.deps()).unwrap();
assert!(!has_pending_result(&ws, parent).unwrap());
}
#[test]
fn run_flush_dispatches_a_compactor_when_the_checkpoint_is_due() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p6";
let wt = fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let wf = workflow(
"events: {}\ncompaction:\n intermediate:\n trigger: every_n_commits\n n: 1\n",
);
run_flush(&ws, parent, &wt, &wf, &fx.deps()).unwrap();
let launched = fx.launcher.launched.borrow();
assert_eq!(launched.len(), 1);
assert!(
launched[0].starts_with(&format!("{parent}-")),
"{launched:?}"
);
}
#[test]
fn run_flush_is_a_noop_without_a_compaction_block() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p7";
let wt = fixture::spawn_root(&ws, parent);
let fx = Fx::new();
run_flush(&ws, parent, &wt, &workflow("events: {}\n"), &fx.deps()).unwrap();
assert!(fx.launcher.launched.borrow().is_empty());
}
fn write_models(fx: &Fx) {
let yaml = "adapter: /bin/true\nmodels:\n \
claude-sonnet-5: {provider: anthropic, model_id: claude-sonnet-5, \
capabilities: [tool_use_native], context_window: 200000}\n \
claude-haiku-4-5: {provider: anthropic, model_id: claude-haiku-4-5, \
capabilities: [tool_use_native], context_window: 200000}\n";
std::fs::write(fx.cfg.path().join("models.yaml"), yaml).unwrap();
}
#[test]
fn resolve_derives_a_dispatched_compactors_role_soul_and_toolset() {
use crate::prompt::resolve::{ConfigSource, resolve_worker};
let (_h, ws) = fixture::workspace();
let parent = "20260101-r1";
fixture::spawn_root(&ws, parent);
let fx = Fx::new();
write_models(&fx);
let parent_wt = agent_worktree(&ws, parent);
let req = ChildDispatchRequest {
repo: &ws,
parent_branch: parent,
parent_worktree: &parent_wt,
role: "compactor",
goal: "compact",
fork_point: None,
};
let child = child_dispatch::run(&req, &fx.git, &fx.clock, &fx.id, &fx.launcher).unwrap();
let cfg = resolve_worker(&ws, ConfigSource::Agent(&child), &fx.deps()).unwrap();
assert_eq!(cfg.role, "compactor");
assert_eq!(cfg.model.model_id, "claude-haiku-4-5");
assert!(
cfg.tools.is_empty(),
"compactor declares no providers.yaml tools"
);
assert!(cfg.soul.to_lowercase().contains("compact"), "{}", cfg.soul);
}
#[test]
fn resolve_defaults_a_root_agent_to_the_worker_role() {
use crate::prompt::resolve::{ConfigSource, resolve_worker};
let (_h, ws) = fixture::workspace();
let root = "20260101-r2";
fixture::spawn_root(&ws, root);
let fx = Fx::new();
write_models(&fx);
let cfg = resolve_worker(&ws, ConfigSource::Agent(root), &fx.deps()).unwrap();
assert_eq!(cfg.role, "worker");
assert_eq!(cfg.model.model_id, "claude-sonnet-5");
}
#[test]
fn run_flush_declines_an_unsupported_flush_action() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-p8";
let wt = fixture::spawn_root(&ws, parent);
let fx = Fx::new();
let wf = workflow(
"events:\n worker_flush:\n - notify_ui\ncompaction:\n intermediate:\n trigger: every_n_commits\n n: 1\n",
);
let err = run_flush(&ws, parent, &wt, &wf, &fx.deps()).unwrap_err();
assert!(matches!(err, Error::ActionUnsupported { .. }), "{err:?}");
}