use super::*;
use crate::prompt::dispatch::assembler;
fn prompt_bytes(wt: &Path) -> usize {
let messages = assembler::assemble(wt, None).unwrap();
serde_json::to_vec(&messages).unwrap().len()
}
fn talkative(n: u32) -> TempDir {
let dir = repo(&[("messages/001-user.md", "the opening prompt\n")]);
let wt = dir.path();
for seq in 2..=n {
let body = format!("entry {seq}: {}\n", "chatter ".repeat(40));
commit(
wt,
&format!("step {seq:03}"),
&[(&format!("messages/{seq:03}-user.md"), body.as_str())],
&[],
);
}
dir
}
fn entries(wt: &Path) -> Vec<String> {
let mut found: Vec<String> = std::fs::read_dir(wt.join("messages"))
.map(|rd| {
rd.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().into_owned())
.collect()
})
.unwrap_or_default();
found.sort();
found
}
#[test]
fn a_landed_compaction_shrinks_the_assembled_prompt() {
let dir = talkative(9);
let wt = dir.path();
let before = prompt_bytes(wt);
compactor(
wt,
&[("summary/001.md", "we talked about widgets\n")],
&[],
&[],
&[],
);
assert_eq!(
land(wt, "p1", "p1-cmp", None, &g()).unwrap(),
LandOutcome::Landed
);
let after = prompt_bytes(wt);
assert!(
after < before,
"a landed compaction must shrink the prompt: {before} -> {after}"
);
assert_eq!(entries(wt), vec!["001-user.md".to_string()]);
assert!(wt.join("summary/001.md").exists(), "the summary landed");
assert_eq!(g().run_capture(wt, &["status", "--porcelain"]).unwrap(), "");
}
#[test]
fn the_live_tail_past_the_compaction_point_is_never_swept() {
let dir = talkative(4);
let wt = dir.path();
compactor(wt, &[("summary/001.md", "digest\n")], &[], &[], &[]);
commit(wt, "step 005", &[("messages/005-user.md", "live\n")], &[]);
assert_eq!(
land(wt, "p1", "p1-cmp", None, &g()).unwrap(),
LandOutcome::Landed
);
assert_eq!(
entries(wt),
vec!["001-user.md".to_string(), "005-user.md".to_string()]
);
}
#[test]
fn a_pass_that_wrote_no_summary_sweeps_nothing() {
let dir = talkative(4);
let wt = dir.path();
compactor(wt, &[], &["messages/003-user.md"], &[], &[]);
assert_eq!(
land(wt, "p1", "p1-cmp", None, &g()).unwrap(),
LandOutcome::Landed
);
assert_eq!(
entries(wt),
vec![
"001-user.md".to_string(),
"002-user.md".to_string(),
"004-user.md".to_string()
]
);
}
#[test]
fn the_extract_reports_the_swept_span_not_only_what_was_nominated() {
let dir = repo(&[
("messages/001-user.md", "the opening prompt\n"),
("messages/002-user.md", "ship the widget\n"),
]);
let wt = dir.path();
compactor(wt, &[("summary/001.md", "digest\n")], &[], &[], &[]);
assert_eq!(
land(wt, "p1", "p1-cmp", Some(4096), &g()).unwrap(),
LandOutcome::Landed
);
let refs = std::fs::read_to_string(wt.join("summary/001.refs.md")).unwrap();
assert!(refs.contains("ship the widget"), "{refs}");
assert!(
!refs.contains("the opening prompt"),
"the dispatch entry never leaves context: {refs}"
);
}