use super::super::run_flush;
use super::{Fx, workflow};
use crate::template::{GitRunner, RealGit};
use crate::workspace::{agent_worktree, fixture};
use std::path::Path;
const BOTH: &str = "events:\n worker_flush:\n - dispatch(compactor)\n - dispatch(reviewer)\ncompaction:\n intermediate:\n trigger: every_n_commits\n n: 1\n";
fn manifest(name: &str, body: &str) -> String {
format!("---\nname: {name}\ndescription: d\n---\n{body}")
}
fn branch_with_a_span(ws: &Path, parent: &str) -> std::path::PathBuf {
let wt = fixture::spawn_root(ws, parent);
let git = RealGit::new();
std::fs::create_dir_all(wt.join("messages")).unwrap();
std::fs::create_dir_all(wt.join("summary")).unwrap();
std::fs::write(wt.join("messages/001-user.md"), "the user said a thing\n").unwrap();
std::fs::write(wt.join("summary/001.md"), "an earlier digest\n").unwrap();
git.run(&wt, &["add", "-A"]).unwrap();
git.run(&wt, &["commit", "-m", "span"]).unwrap();
wt
}
fn fork_parent(wt: &Path, child: &str) -> String {
RealGit::new()
.run_capture(
wt,
&[
"rev-parse",
&format!("{}~1", crate::workspace::agent_ref(child)),
],
)
.unwrap()
}
#[test]
fn one_due_clock_forks_a_compactor_and_a_reviewer_off_one_point() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-r1";
let wt = branch_with_a_span(&ws, parent);
fixture::amend_config(
&ws,
&[(
"skills/notes/SKILL.md",
manifest("notes", "the lesson").as_str(),
)],
);
let fx = Fx::new();
run_flush(&ws, parent, &wt, &workflow(BOTH), &fx.deps()).unwrap();
let launched = fx.launcher.launched.borrow().clone();
assert_eq!(launched.len(), 2, "one clock, two forks: {launched:?}");
let point = RealGit::new()
.run_capture(&wt, &["rev-parse", "HEAD"])
.unwrap();
for child in &launched {
assert_eq!(
fork_parent(&wt, child),
point,
"{child} forked off the point"
);
}
let reviewer = agent_worktree(&ws, &launched[1]);
assert!(reviewer.join("messages/001-user.md").exists());
assert!(reviewer.join("summary/001.md").exists());
assert!(
agent_worktree(&ws, &launched[0])
.join("messages/001-user.md")
.exists(),
"the compactor keeps it too"
);
assert_eq!(
std::fs::read_to_string(reviewer.join("skills/notes/SKILL.md")).unwrap(),
manifest("notes", "the lesson"),
);
assert!(
!wt.join("skills/notes/SKILL.md").exists(),
"not the parent's"
);
}
#[test]
fn a_worker_child_forked_at_a_checkpoint_carries_no_dialog_and_no_bodies() {
use crate::prompt::child_dispatch::{ChildDispatchRequest, run as dispatch_child};
let (_h, ws) = fixture::workspace();
let parent = "20260101-r2";
let wt = branch_with_a_span(&ws, parent);
fixture::amend_config(
&ws,
&[(
"skills/notes/SKILL.md",
manifest("notes", "the lesson").as_str(),
)],
);
let fx = Fx::new();
let req = ChildDispatchRequest {
repo: &ws,
parent_branch: parent,
parent_worktree: &wt,
role: "worker",
goal: "do it",
name: None,
fork_point: None,
cwd: None,
pins: crate::prompt::PinnedDocs::none(),
};
let child = dispatch_child(
&req,
&fx.git,
&fx.clock,
&fx.id,
&fx.launcher,
crate::workspace::agent_name::mint::test_rng(),
)
.unwrap();
let cwt = agent_worktree(&ws, &child);
assert!(!cwt.join("messages/001-user.md").exists());
assert!(!cwt.join("summary/001.md").exists());
assert!(!cwt.join("skills/notes/SKILL.md").exists());
}
#[test]
fn the_reviewers_read_is_the_config_commits_body_not_the_forked_copy() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-r3";
let wt = branch_with_a_span(&ws, parent);
let git = RealGit::new();
std::fs::create_dir_all(wt.join("skills/notes")).unwrap();
std::fs::write(
wt.join("skills/notes/SKILL.md"),
manifest("notes", "the stale lesson"),
)
.unwrap();
git.run(&wt, &["add", "-A"]).unwrap();
git.run(&wt, &["commit", "-m", "elected"]).unwrap();
fixture::amend_config(
&ws,
&[(
"skills/notes/SKILL.md",
manifest("notes", "the current lesson").as_str(),
)],
);
let fx = Fx::new();
run_flush(&ws, parent, &wt, &workflow(BOTH), &fx.deps()).unwrap();
let reviewer = agent_worktree(&ws, &fx.launcher.launched.borrow()[1]);
assert_eq!(
std::fs::read_to_string(reviewer.join("skills/notes/SKILL.md")).unwrap(),
manifest("notes", "the current lesson"),
);
}
#[test]
fn the_reviewer_carries_the_facts_document_when_the_lineage_has_one() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-r4";
let wt = branch_with_a_span(&ws, parent);
fixture::amend_config(&ws, &[("facts.md", "the box has no network\n")]);
let fx = Fx::new();
run_flush(&ws, parent, &wt, &workflow(BOTH), &fx.deps()).unwrap();
let reviewer = agent_worktree(&ws, &fx.launcher.launched.borrow()[1]);
assert_eq!(
std::fs::read_to_string(reviewer.join("facts.md")).unwrap(),
"the box has no network\n"
);
}
#[test]
fn a_lineage_carrying_neither_class_checks_out_nothing() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-r5";
let wt = branch_with_a_span(&ws, parent);
let fx = Fx::new();
run_flush(&ws, parent, &wt, &workflow(BOTH), &fx.deps()).unwrap();
let reviewer = agent_worktree(&ws, &fx.launcher.launched.borrow()[1]);
assert!(!reviewer.join("facts.md").exists());
assert!(!reviewer.join("skills").exists());
assert!(
reviewer.join("messages/001-user.md").exists(),
"still forked"
);
}
#[test]
fn a_checkpoint_dispatch_of_a_role_with_no_goal_is_declined() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-r6";
let wt = branch_with_a_span(&ws, parent);
let fx = Fx::new();
let wf = workflow(
"events:\n worker_flush:\n - dispatch(worker)\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, crate::prompt::Error::ActionUnsupported { ref event, .. } if event == &"worker_flush"),
"{err:?}"
);
assert!(fx.launcher.launched.borrow().is_empty());
}
#[test]
fn a_reviewer_branch_dispatches_nothing_at_its_own_boundary() {
let (_h, ws) = fixture::workspace();
let parent = "20260101-r7";
let wt = branch_with_a_span(&ws, parent);
fixture::amend_config(
&ws,
&[("souls/compactor.md", "c"), ("souls/reviewer.md", "r")],
);
let fx = Fx::new();
let wf = workflow(BOTH);
run_flush(&ws, parent, &wt, &wf, &fx.deps()).unwrap();
let minted = fx.launcher.launched.borrow().clone();
assert_eq!(
minted.len(),
2,
"one compactor and one reviewer: {minted:?}"
);
for child in &minted {
let child_wt = agent_worktree(&ws, child);
std::fs::write(child_wt.join("goal.md"), format!("step for {child}")).unwrap();
RealGit::new().run(&child_wt, &["add", "-A"]).unwrap();
RealGit::new()
.run(&child_wt, &["commit", "-m", "step"])
.unwrap();
run_flush(&ws, child, &child_wt, &wf, &fx.deps()).unwrap();
}
assert_eq!(
fx.launcher.launched.borrow().len(),
2,
"machinery mints no machinery: {:?}",
fx.launcher.launched.borrow()
);
}