use crate::facts::FILE;
use crate::prompt::Error;
use crate::prompt::dispatch::{Grant, trim_to_context};
use crate::template::{GitRunner, RealGit};
use crate::workspace::{config_ref, fixture, repo_git};
use std::path::Path;
fn config_tip(ws: &Path) -> String {
RealGit::new()
.run_capture(&repo_git(ws), &["rev-parse", &config_ref("default")])
.unwrap()
}
fn trim(wt: &Path, commit: &str, git: &dyn GitRunner) -> Result<(), Error> {
let grant = Grant {
role: "worker",
tools: &[],
config_commit: commit,
};
trim_to_context(wt, "20260101-f1", &grant, None, git)
}
#[test]
fn a_commit_carrying_facts_yields_a_tree_carrying_them() {
let (_h, ws) = fixture::workspace();
fixture::amend_config(&ws, &[(FILE, "the build runs on nightly\n")]);
let wt = fixture::spawn_root(&ws, "a1");
trim(&wt, &config_tip(&ws), &RealGit::new()).unwrap();
assert_eq!(
std::fs::read_to_string(wt.join(FILE)).unwrap(),
"the build runs on nightly\n"
);
let tracked = RealGit::new()
.run_capture(&wt, &["ls-files", "--", FILE])
.unwrap();
assert_eq!(tracked.trim(), FILE);
}
#[test]
fn a_child_gets_the_followed_commits_bytes_over_its_parents_stale_copy() {
let (_h, ws) = fixture::workspace();
fixture::amend_config(&ws, &[(FILE, "old\n")]);
let parent = fixture::spawn_root(&ws, "a1");
assert_eq!(std::fs::read_to_string(parent.join(FILE)).unwrap(), "old\n");
fixture::amend_config(&ws, &[(FILE, "new\n")]);
let child = fixture::spawn_agent(&ws, "a1-c1", "agents/a1");
trim(&child, &config_tip(&ws), &RealGit::new()).unwrap();
assert_eq!(std::fs::read_to_string(child.join(FILE)).unwrap(), "new\n");
let staged = RealGit::new()
.run_capture(&child, &["diff", "--cached", "--name-status"])
.unwrap();
assert!(
staged.lines().any(|l| l == format!("M\t{FILE}")),
"{staged:?}"
);
}
#[test]
fn absent_in_the_commit_is_absent_in_the_tree() {
let (_h, ws) = fixture::workspace();
let before = config_tip(&ws);
fixture::amend_config(&ws, &[(FILE, "old\n")]);
let wt = fixture::spawn_root(&ws, "a1");
assert!(wt.join(FILE).exists());
trim(&wt, &before, &RealGit::new()).unwrap();
assert!(!wt.join(FILE).exists());
let staged = RealGit::new()
.run_capture(&wt, &["diff", "--cached", "--name-status"])
.unwrap();
assert!(
staged.lines().any(|l| l == format!("D\t{FILE}")),
"{staged:?}"
);
}
#[test]
fn no_facts_anywhere_is_a_no_op() {
let (_h, ws) = fixture::workspace();
let wt = fixture::spawn_root(&ws, "a1");
trim(&wt, &config_tip(&ws), &RealGit::new()).unwrap();
assert!(!wt.join(FILE).exists());
}
#[test]
fn a_refused_cut_surfaces_as_a_named_git_error() {
struct RefusesFactsCheckout(RealGit);
impl GitRunner for RefusesFactsCheckout {
fn run(&self, dest: &Path, args: &[&str]) -> std::io::Result<()> {
if args.first() == Some(&"checkout") && args.contains(&FILE) {
return Err(std::io::Error::other("checkout refused"));
}
self.0.run(dest, args)
}
fn run_capture(&self, dest: &Path, args: &[&str]) -> std::io::Result<String> {
self.0.run_capture(dest, args)
}
}
let (_h, ws) = fixture::workspace();
fixture::amend_config(&ws, &[(FILE, "a fact\n")]);
let wt = fixture::spawn_root(&ws, "a1");
let err = trim(&wt, &config_tip(&ws), &RefusesFactsCheckout(RealGit::new())).unwrap_err();
assert!(
matches!(&err, Error::Git { op, .. } if *op == "cut the facts file"),
"{err}"
);
}