pub(crate) fn summarize_text_for_visibility(text: &str, max_chars: usize) -> String {
let normalized = text.split_whitespace().collect::<Vec<_>>().join(" ");
if normalized.chars().count() <= max_chars {
return normalized;
}
normalized
.chars()
.take(max_chars.saturating_sub(3))
.collect::<String>()
+ "..."
}
fn is_policy_or_code_sensitive_text(text: &str) -> bool {
let lower = text.to_ascii_lowercase();
[
"error",
"failed",
"blocked",
"fallback",
"reclaim",
"reassign",
"restart",
"ghost",
"sentinel",
"check-install",
"evidence_path",
"evidence paths",
"unauthorized",
"permission denied",
]
.iter()
.any(|needle| lower.contains(needle))
|| text.contains("```")
|| text.contains('{')
|| text.contains('}')
}
fn is_removable_filler_token(token: &str) -> bool {
let word = token
.trim_matches(|character: char| !character.is_ascii_alphabetic())
.to_ascii_lowercase();
matches!(
word.as_str(),
"a" | "an"
| "the"
| "that"
| "this"
| "these"
| "those"
| "very"
| "really"
| "basically"
| "simply"
| "just"
| "please"
| "likely"
| "probably"
| "generally"
| "actually"
| "currently"
)
}
pub(crate) fn compact_prose_for_visibility(text: &str, max_chars: usize) -> String {
let normalized = text.split_whitespace().collect::<Vec<_>>().join(" ");
if normalized.is_empty() || is_policy_or_code_sensitive_text(&normalized) {
return summarize_text_for_visibility(&normalized, max_chars);
}
let compact = normalized
.split_whitespace()
.filter(|token| !is_removable_filler_token(token))
.collect::<Vec<_>>()
.join(" ");
let compact = if compact.trim().is_empty() {
normalized
} else {
compact
};
summarize_text_for_visibility(&compact, max_chars)
}
fn normalize_compact_text(text: &str) -> String {
text.split_whitespace().collect::<Vec<_>>().join(" ")
}
pub(crate) fn compact_prompt_text(text: &str, max_chars: usize) -> String {
summarize_text_for_visibility(text, max_chars.max(24))
}
pub(crate) fn prompt_fields_match(left: &str, right: &str) -> bool {
!left.trim().is_empty() && normalize_compact_text(left) == normalize_compact_text(right)
}
#[cfg(test)]
mod tests {
use super::{compact_prose_for_visibility, summarize_text_for_visibility};
#[test]
fn compact_prose_removes_filler_but_preserves_code_like_tokens() {
let text =
"The implementation simply updates rust/ccc-mcp/src/main.rs and keeps run_id exact.";
let compact = compact_prose_for_visibility(text, 160);
assert!(!compact.contains(" simply "));
assert!(compact.contains("rust/ccc-mcp/src/main.rs"));
assert!(compact.contains("run_id"));
}
#[test]
fn compact_prose_does_not_rewrite_policy_or_error_text() {
let text = "Ghost/Sentinel fallback blocked because error status must stay exact.";
assert_eq!(
compact_prose_for_visibility(text, 160),
summarize_text_for_visibility(text, 160)
);
}
}