use crate::brain::agent::service::tool_loop::{
ACCOUNT_ROTATION_ALERT, CONTINUATION_EMPTY_ALERT, EMPTY_ANSWER_ANALYSIS_ALERT,
PHANTOM_RETRY_ENFORCEMENT_ALERT, SELF_HEAL_BUDGET_ROLLED_ALERT, SELF_HEAL_EXHAUSTED_ALERT,
};
use crate::brain::agent::service::truncation::{CONTINUATION_NUDGE_ALERT, INCOMPLETE_MARKER};
use std::fs;
use std::path::{Path, PathBuf};
#[test]
fn alert_constants_carry_no_typographic_dashes() {
let consts: [(&str, &str); 8] = [
(
"PHANTOM_RETRY_ENFORCEMENT_ALERT",
PHANTOM_RETRY_ENFORCEMENT_ALERT,
),
(
"SELF_HEAL_BUDGET_ROLLED_ALERT",
SELF_HEAL_BUDGET_ROLLED_ALERT,
),
("SELF_HEAL_EXHAUSTED_ALERT", SELF_HEAL_EXHAUSTED_ALERT),
("ACCOUNT_ROTATION_ALERT", ACCOUNT_ROTATION_ALERT),
("CONTINUATION_EMPTY_ALERT", CONTINUATION_EMPTY_ALERT),
("EMPTY_ANSWER_ANALYSIS_ALERT", EMPTY_ANSWER_ANALYSIS_ALERT),
("CONTINUATION_NUDGE_ALERT", CONTINUATION_NUDGE_ALERT),
("INCOMPLETE_MARKER", INCOMPLETE_MARKER),
];
for (name, text) in consts {
assert!(
!text.contains('\u{2014}') && !text.contains('\u{2013}'),
"{name} carries a typographic dash: {text:?}"
);
}
}
#[test]
fn every_self_healing_renderer_normalizes_dashes() {
let src = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
let mut files = Vec::new();
collect_rs_files(&src, &mut files);
assert!(
files.len() > 100,
"source walk found nothing under {:?}; cwd={:?}",
src,
std::env::current_dir()
);
let mut violations = Vec::new();
for file in &files {
let rel = file
.strip_prefix(&src)
.expect("walk root is src")
.to_string_lossy()
.replace('\\', "/");
if rel.starts_with("tests/") {
continue;
}
let Ok(content) = fs::read_to_string(file) else {
continue;
};
if content.contains("ProgressEvent::SelfHealingAlert { message } =>")
&& !content.contains("normalize_dashes")
{
violations.push(rel);
}
}
assert!(
violations.is_empty(),
"files rendering SelfHealingAlert without normalize_dashes: {violations:?}"
);
}
#[test]
fn trello_outbound_funnels_through_the_boundary() {
let client = Path::new(env!("CARGO_MANIFEST_DIR")).join("src/channels/trello/client.rs");
let content = fs::read_to_string(&client)
.unwrap_or_else(|e| panic!("cannot read {}: {e}", client.display()));
assert!(
content.contains("async fn add_comment_to_card("),
"add_comment_to_card moved or renamed; re-verify the Trello boundary (#1970)"
);
assert!(
content.contains("strip_llm_artifacts"),
"Trello client no longer routes outbound comments through \
strip_llm_artifacts (#1970 regression)"
);
}
fn collect_rs_files(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_rs_files(&path, out);
} else if path.extension().is_some_and(|ext| ext == "rs") {
out.push(path);
}
}
}