use super::*;
#[test]
fn sweep_deposits_died_for_a_child_that_never_returned() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&["main", PARENT, CHILD]).tip(CHILD, "cafef00d");
let launcher = StubLauncher::default();
let report = scan(ws.path(), &git, &FixedClock, &launcher).unwrap();
assert_eq!(report.swept, vec![CHILD.to_string()]);
assert_eq!(report.silent_deaths, vec![CHILD.to_string()]);
let deposited = inbox_dir(ws.path(), PARENT).join(format!("{CHILD}-001.md"));
let body = std::fs::read_to_string(&deposited).unwrap();
assert!(
body.contains(&format!("from: {CHILD}")),
"sender is the child"
);
assert!(body.contains("epitaph: died"));
assert!(body.contains("terminal_ref: cafef00d"));
assert_eq!(report.flushed, vec![PARENT.to_string()]);
assert_eq!(launcher.invocations(), vec![PARENT.to_string()]);
}
#[test]
fn sweep_is_idempotent_across_a_double_scan() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&["main", PARENT, CHILD]);
let launcher = StubLauncher::default();
let first = scan(ws.path(), &git, &FixedClock, &launcher).unwrap();
assert_eq!(first.swept, vec![CHILD.to_string()]);
let second = scan(ws.path(), &git, &FixedClock, &launcher).unwrap();
assert!(second.swept.is_empty(), "no re-deposit on re-scan");
assert!(second.silent_deaths.is_empty());
let count = std::fs::read_dir(inbox_dir(ws.path(), PARENT))
.unwrap()
.flatten()
.filter(|e| e.file_name().to_string_lossy().starts_with(CHILD))
.count();
assert_eq!(count, 1, "exactly one died deposit");
}
#[test]
fn child_with_a_delivered_transcript_message_is_not_swept() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&["main", PARENT, CHILD])
.ls_tree(PARENT, &format!("messages/003-{CHILD}.md\n"));
let report = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap();
assert!(
report.swept.is_empty(),
"delivered return counts as returned"
);
assert!(report.silent_deaths.is_empty());
}
#[test]
fn child_with_an_undelivered_inbox_message_is_not_swept() {
let ws = TempDir::new().unwrap();
deposit_msg(ws.path(), PARENT, &format!("{CHILD}-001.md"));
let git = StubGit::with_branches(&["main", PARENT, CHILD]);
let report = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap();
assert!(report.swept.is_empty());
assert!(report.silent_deaths.is_empty());
}
#[test]
fn a_driven_child_is_never_swept() {
let ws = TempDir::new().unwrap();
let _held = try_acquire(&inbox_dir(ws.path(), CHILD))
.unwrap()
.expect("free");
let git = StubGit::with_branches(&["main", PARENT, CHILD]);
let report = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap();
assert!(report.swept.is_empty(), "held lock is not a silent death");
assert!(report.silent_deaths.is_empty());
}
#[test]
fn a_root_is_counted_but_never_deposited() {
let ws = TempDir::new().unwrap();
write_response(ws.path(), PARENT, "001", KILLED);
let git = StubGit::with_branches(&["main", PARENT]);
let report = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap();
assert!(report.swept.is_empty(), "a root has no parent inbox");
assert_eq!(
report.silent_deaths,
vec![PARENT.to_string()],
"died-mid-work root is a silent death, surfaced by name"
);
}
#[test]
fn a_root_with_a_failed_model_call_is_a_named_silent_death() {
let ws = TempDir::new().unwrap();
write_response(ws.path(), PARENT, "001", FAILED);
let git = StubGit::with_branches(&["main", PARENT]);
let report = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap();
assert!(report.swept.is_empty(), "a root gets no deposit");
assert_eq!(report.silent_deaths, vec![PARENT.to_string()]);
assert!(
report
.to_string()
.contains(&format!("silent deaths: 1 ({PARENT})")),
"{report}"
);
}
#[test]
fn a_branch_whose_derived_parent_has_no_ref_is_treated_as_a_root() {
let ws = TempDir::new().unwrap();
let orphan = format!("{PARENT}-c0ffee");
assert_eq!(parent_of(&orphan).as_deref(), Some("20260101"));
deposit_msg(ws.path(), PARENT, "user-001.md");
let git = StubGit::with_branches(&[PARENT, orphan.as_str()]);
let launcher = StubLauncher::default();
let report = scan(ws.path(), &git, &FixedClock, &launcher).unwrap();
assert!(report.swept.is_empty(), "no parent inbox to deposit into");
assert!(
report.silent_deaths.is_empty(),
"alive-and-quiet, like a root"
);
assert!(
!git.asked_ls_tree_for("20260101"),
"no git question about a ref the registry does not hold"
);
assert_eq!(report.flushed, vec![PARENT.to_string()]);
assert_eq!(launcher.invocations(), vec![PARENT.to_string()]);
}
#[test]
fn an_absent_parent_inbox_reads_as_no_undelivered_return() {
let ws = TempDir::new().unwrap();
assert!(!inbox_dir(ws.path(), PARENT).exists());
assert!(!returned(ws.path(), &StubGit::default(), PARENT, CHILD).unwrap());
}
#[test]
fn died_mid_work_reads_the_latest_step_response() {
let ws = TempDir::new().unwrap();
write_response(ws.path(), PARENT, "001", COMPLETE);
write_response(ws.path(), PARENT, "002", KILLED);
assert!(died_mid_work(ws.path(), PARENT));
}
#[test]
fn a_failed_latest_response_is_a_death() {
let ws = TempDir::new().unwrap();
write_response(ws.path(), PARENT, "001", FAILED);
assert!(died_mid_work(ws.path(), PARENT));
}
#[test]
fn a_complete_latest_response_is_not_a_death() {
let ws = TempDir::new().unwrap();
write_response(ws.path(), PARENT, "001", KILLED);
write_response(ws.path(), PARENT, "002", COMPLETE);
assert!(!died_mid_work(ws.path(), PARENT));
}
#[test]
fn no_steps_tree_is_not_a_death() {
let ws = TempDir::new().unwrap();
assert!(
!died_mid_work(ws.path(), CHILD),
"shipped child shape: no steps/"
);
std::fs::create_dir_all(ws.path().join(STEPS_DIR).join(CHILD).join("junk")).unwrap();
assert!(!died_mid_work(ws.path(), CHILD));
std::fs::create_dir_all(ws.path().join(STEPS_DIR).join(CHILD).join("001")).unwrap();
assert!(!died_mid_work(ws.path(), CHILD));
}