use crate::brain::agent::service::phantom::is_structured_report;
const TOOL_LOOP_SRC: &str = include_str!("../brain/agent/service/tool_loop.rs");
const BATCH_REPORT: &str = "Batch done. 13/13 tasks, all 10 PRs merged locally.\n\
\n\
| Merge | PR | Surface |\n\
|---|---|---|\n\
| `8b1e1928` | #1503 | +761, 8 files |\n\
| `147f434b` | #1501 | exclusion list |\n\
\n\
Gates: check 0, clippy 0, suite 8228 passed / 0 failed.\n";
#[test]
fn a_batch_report_with_a_verdict_table_is_structured() {
assert!(is_structured_report(BATCH_REPORT));
}
#[test]
fn a_table_needs_a_data_row_not_just_a_separator() {
let header_only = "Gate | Verdict |\n|---|---|\nprose continues here, no rows follow";
assert!(!is_structured_report(header_only));
}
#[test]
fn an_alphanumeric_pipe_row_is_data_never_a_separator() {
let no_separator = "| Gate | Verdict |\n| a--b | c--d |\n| e | f |";
assert!(!is_structured_report(no_separator));
let with_separator = "| Gate | Verdict |\n|---|---|\n| a | b |";
assert!(is_structured_report(with_separator));
}
#[test]
fn two_section_headings_are_a_structured_document() {
let doc = "## What landed\n\nProse paragraph.\n\n## Gates\n\nMore prose.\n";
assert!(is_structured_report(doc));
}
#[test]
fn one_heading_is_not_enough() {
let one = "## Summary\n\nCommitted as deadbeef42 and pushed.\n";
assert!(!is_structured_report(one));
}
#[test]
fn prose_fabrications_are_never_structured() {
for text in [
"Done.",
"Pushed to origin.",
"Committed as deadbeef42, tests green.",
"Batch done. 13/13 tasks, all merged locally, CI green.",
"I'll dig into the delete endpoint, the send path, and the flow.",
] {
assert!(
!is_structured_report(text),
"{text:?} wrongly classed as structured"
);
}
}
#[test]
fn a_table_buried_in_prose_still_counts() {
let buried = "All work is committed and the tree is clean.\n\
\n\
| Commit | What |\n\
|---|---|\n\
| abc1234 | the fix |\n\
\n\
Push next.\n";
assert!(is_structured_report(buried));
}
#[test]
fn an_indented_or_padded_table_still_counts() {
let padded = "Receipts:\n\n | Gate | Exit |\n |---|---|\n | check | 0 |\n";
assert!(is_structured_report(padded));
}
#[test]
fn the_kill_block_builds_a_named_branch_list() {
let list = TOOL_LOOP_SRC
.split("let fired_branches")
.nth(1)
.expect("fired_branches list not found in tool_loop");
let list = list.split("];").next().expect("unterminated list");
for label in [
"intent_no_tools",
"intent_full_text",
"tool_name_narrated",
"shell_fence_narrated",
"unbacked_side_effects",
"bare_completion_delivery",
"media_claim_no_marker",
"uncalled_commands",
"unbacked_evidence",
"unbacked_facts",
] {
assert!(list.contains(label), "branch label `{label}` missing");
}
}
#[test]
fn the_warn_carries_the_branch_names() {
let block = TOOL_LOOP_SRC
.split("Phantom tool call detected")
.nth(1)
.expect("phantom WARN not found");
let block = block.split('\n').take(4).collect::<Vec<_>>().join("\n");
assert!(
block.contains("branches={:?}") || block.contains("branches = ?"),
"the phantom WARN does not name the fired branches: {block}"
);
}
#[test]
fn the_kill_gate_consults_the_structured_report_check() {
assert!(
TOOL_LOOP_SRC.contains("let structured_report ="),
"the kill block never computes the structured-report classification"
);
assert!(
TOOL_LOOP_SRC.contains("super::phantom::is_structured_report(&iteration_text)"),
"the kill block does not consult is_structured_report"
);
}
#[test]
fn the_exempt_path_is_suppression_not_a_branch_of_the_kill() {
let gate = TOOL_LOOP_SRC
.split("if kill && structured_report")
.nth(1)
.expect("suppression branch not found");
let gate = gate
.split("} else if kill {")
.next()
.expect("kill branch not found");
assert!(
gate.contains("phantom suppressed"),
"the suppression path is not logged"
);
assert!(
!gate.contains("phantom_detections_total += 1"),
"the suppression path burns the retry budget — it must not"
);
assert!(
!gate.contains("StripStreamedContent"),
"the suppression path drains the streamed report — the exact #1506 bug"
);
}
#[test]
fn the_kill_still_requires_a_fired_branch_and_budget() {
let gate = TOOL_LOOP_SRC
.split("let kill =")
.nth(1)
.expect("kill gate not found");
let gate = gate.split(';').next().unwrap();
assert!(gate.contains("phantom_retries_used < MAX_PHANTOM_RETRIES"));
assert!(gate.contains("phantom_detections_total < MAX_PHANTOM_DETECTIONS_TOTAL"));
assert!(gate.contains("phantom_eligible"));
assert!(gate.contains("!fired_branches.is_empty()"));
}
#[test]
fn the_suppressed_report_logs_its_branches_for_forensics() {
let gate = TOOL_LOOP_SRC
.split("if kill && structured_report")
.nth(1)
.expect("suppression branch not found");
let gate = gate.split("} else if kill {").next().unwrap();
assert!(
gate.contains("branches = ?fired_branches"),
"the suppression WARN does not name the fired branches"
);
assert!(
gate.contains("text_len"),
"the suppression WARN lacks a size breadcrumb"
);
}