const TOOL_LOOP: &str = "src/brain/agent/service/tool_loop.rs";
fn tool_loop_src() -> String {
std::fs::read_to_string(TOOL_LOOP).expect("tool_loop.rs must be readable")
}
#[test]
fn blocked_iterations_persist_under_the_phantom_flag() {
let src = tool_loop_src();
let branch = src
.find("if iteration_is_phantom {")
.expect("the phantom persist branch must exist");
let tail = &src[branch..branch + 3000];
assert!(
tail.contains("phantom_blocked=1"),
"blocked iterations must carry the phantom_blocked=1 marker so a \
classified-as-phantom deliverable stays recoverable from the DB"
);
assert!(
tail.contains("append_content"),
"the flagged iteration must actually be written to the message store"
);
assert!(
!tail.contains("pending_phantom_content"),
"the stash-and-flush mechanism (#458) is superseded; nothing may be \
withheld any more"
);
}
#[test]
fn flagged_persist_does_not_reach_the_user_surface() {
let src = tool_loop_src();
let branch = src
.find("if iteration_is_phantom {")
.expect("the phantom persist branch must exist");
let else_pos = src[branch..]
.find("} else {")
.expect("phantom arm must be followed by an else")
+ branch;
let arm = &src[branch..else_pos];
assert!(
!arm.contains("accumulated_text.push_str"),
"a phantom-blocked iteration must never enter accumulated_text — \
the user still sees none of it"
);
}
#[test]
fn both_detection_sites_count_toward_the_ceiling() {
let src = tool_loop_src();
let hits = src.matches("phantom_detections_total += 1;").count();
assert_eq!(
hits, 2,
"exactly two increment sites expected: the ThinkingLoopTimeout arm \
and the main phantom-detection arm"
);
}
#[test]
fn retry_gates_check_the_global_ceiling() {
let src = tool_loop_src();
let hits = src
.matches("&& phantom_detections_total < MAX_PHANTOM_DETECTIONS_TOTAL")
.count();
assert!(
hits >= 3,
"the ceiling gate must appear in the timeout guard, the main retry \
gate and the roll guard; found {hits}"
);
}
#[test]
fn give_up_fires_when_the_ceiling_trips() {
let src = tool_loop_src();
assert!(
src.contains("|| phantom_detections_total >= MAX_PHANTOM_DETECTIONS_TOTAL"),
"the give-up gate must accept the global ceiling as an exhaustion \
condition, or a swapped-in provider's fresh budget keeps the loop alive"
);
}
#[test]
fn rolls_cannot_rescue_a_spent_ceiling() {
let src = tool_loop_src();
let roll = src
.find("if phantom_rolls < MAX_PHANTOM_ROLLS")
.expect("the roll guard must exist");
let tail = &src[roll..roll + 400];
assert!(
tail.contains("phantom_detections_total < MAX_PHANTOM_DETECTIONS_TOTAL"),
"a roll resets the retry counter and re-nudges — allowed past a spent \
ceiling, it would defeat the budget entirely"
);
}
#[test]
fn ceiling_is_derived_from_the_documented_formula() {
let src = tool_loop_src();
assert!(
src.contains("MAX_PHANTOM_DETECTIONS_TOTAL: u32")
&& src.contains("MAX_PHANTOM_RETRIES * (MAX_PHANTOM_ROLLS + 1)"),
"the ceiling must stay tied to the per-provider budget constants so the \
two stay coherent"
);
}
#[test]
fn the_turn_close_flush_is_retired() {
let src = tool_loop_src();
assert!(
!src.contains("pending_phantom_content"),
"#458's stash was superseded by detection-time persistence; leftover \
references mean the removal was incomplete"
);
}