use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use supercode::reduce::{
content_hash, invert, invert_one, prepare_read_freshness, probe_read_freshness, project,
project_messages, reduce_to_fit, reduction_id, ReductionKind, ReductionLog, ReductionPolicy,
REDUCTION_SENTINEL,
};
use supercode::{ChatMessage, FunctionCall, Role, Session, ToolCall};
fn fixture(name: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures")
.join(name)
}
#[test]
fn prepared_stale_reads_count_before_context_pressure_escalation() {
let dir = a8_temp_dir("preflight-pressure");
let file_path = dir.join("f.txt");
let content = eight_kb_content();
std::fs::write(&file_path, &content).unwrap();
let msgs = vec![
ChatMessage::user("please read the file"),
read_call("call_1", &file_path),
ChatMessage::tool_result("call_1", "read_file", content),
];
let mut policy = ReductionPolicy {
elide_stale_reads: true,
protect_last_n_tool_results: 0,
..ReductionPolicy::default()
};
prepare_read_freshness(&mut policy, &msgs);
let (base_view, _) = project_messages(&msgs, &policy, &ReductionLog::default());
let fit_bytes = serde_json::to_vec(&base_view).unwrap().len();
let (_view, log, applied) =
reduce_to_fit(&msgs, &policy, &ReductionLog::default(), |candidate| {
serde_json::to_vec(candidate).unwrap().len() <= fit_bytes
});
assert_eq!(
applied, policy,
"verified stale-read savings must satisfy preflight at the base policy"
);
assert_eq!(log.reductions.len(), 1);
assert!(matches!(
log.reductions[0].kind,
ReductionKind::FileReadElided { .. }
));
std::fs::remove_dir_all(dir).ok();
}
fn load_codex() -> Session {
Session::from_codex(fixture("codex_session.jsonl")).unwrap()
}
fn load_claude() -> Session {
Session::from_claude_code(fixture("claude_code_session.jsonl")).unwrap()
}
fn tool_indices(session: &Session) -> Vec<usize> {
session
.messages
.iter()
.enumerate()
.filter(|(_, m)| m.role == Role::Tool)
.map(|(i, _)| i)
.collect()
}
fn pad_tool_output(session: &mut Session, ordinal: usize, target_len: usize) {
let idx = tool_indices(session)[ordinal];
let filler: String = (0..target_len)
.map(|i| (b'a' + (i % 26) as u8) as char)
.collect();
session.messages[idx].content = Some(filler);
}
fn append_synthetic_turns(session: &mut Session, n: usize) {
for i in 0..n {
session
.messages
.push(ChatMessage::user(format!("synthetic follow-up {i}")));
session
.messages
.push(ChatMessage::assistant(format!("synthetic reply {i}")));
}
}
fn tool_calls_identical(a: &[ToolCall], b: &[ToolCall]) -> bool {
a.len() == b.len()
&& a.iter().zip(b).all(|(x, y)| {
x.id == y.id
&& x.kind == y.kind
&& x.function.name == y.function.name
&& x.function.arguments == y.function.arguments
})
}
fn messages_identical(a: &[ChatMessage], b: &[ChatMessage]) -> bool {
a.len() == b.len()
&& a.iter().zip(b).all(|(x, y)| {
x.role == y.role
&& x.content == y.content
&& x.content_parts == y.content_parts
&& x.tool_call_id == y.tool_call_id
&& x.name == y.name
&& x.metadata == y.metadata
&& tool_calls_identical(x.tool_calls(), y.tool_calls())
})
}
fn strip_sc(meta: &BTreeMap<String, String>) -> BTreeMap<String, String> {
meta.iter()
.filter(|(k, _)| !k.starts_with("sc."))
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
}
fn msg_eq_ext(a: &ChatMessage, b: &ChatMessage) -> bool {
if a.role != b.role
|| a.content != b.content
|| a.content_parts != b.content_parts
|| a.tool_call_id != b.tool_call_id
{
return false;
}
let (ca, cb) = (a.tool_calls(), b.tool_calls());
if ca.len() != cb.len() {
return false;
}
let calls_ok = ca.iter().zip(cb).all(|(x, y)| {
x.id == y.id
&& x.function.name == y.function.name
&& x.function.parsed_arguments().ok() == y.function.parsed_arguments().ok()
});
calls_ok && strip_sc(&a.metadata) == strip_sc(&b.metadata)
}
fn assert_identity(label: &str, inverted: &[ChatMessage], original: &[ChatMessage]) {
assert_eq!(
inverted.len(),
original.len(),
"{label}: message count changed after invert(project(..))"
);
for (i, (x, y)) in inverted.iter().zip(original).enumerate() {
assert!(
msg_eq_ext(x, y),
"{label}: message {i} differs after invert(project(..)):\n inverted: {x:?}\n original: {y:?}"
);
}
}
fn big_data_url(mime: &str, payload_len: usize) -> String {
format!("data:{mime};base64,{}", "A".repeat(payload_len))
}
fn forcing_policy() -> ReductionPolicy {
ReductionPolicy {
tool_output_keep_bytes: 64,
tool_output_trigger_bytes: 128,
protect_last_n_tool_results: 0,
..ReductionPolicy::default()
}
}
#[test]
fn project_is_deterministic_and_prefix_stable() {
let mut session = load_codex();
pad_tool_output(&mut session, 0, 100_000);
let policy = forcing_policy();
let prior = ReductionLog::default();
let (view1, log1) = project(&session, &policy, &prior);
let (view2, log2) = project(&session, &policy, &prior);
assert!(
messages_identical(&view1, &view2),
"project() is not deterministic: two runs over identical inputs produced different views"
);
assert_eq!(
log1, log2,
"project() is not deterministic: two runs over identical inputs produced different logs"
);
assert!(
!log1.reductions.is_empty(),
"the 100 KB padded tool output should have triggered at least one reduction"
);
let mut grown = session.clone();
append_synthetic_turns(&mut grown, 1);
let (view3, log3) = project(&grown, &policy, &log1);
assert_eq!(
log3.reductions.len(),
log1.reductions.len(),
"re-projecting an already-fully-reduced session with a stable prior log should not \
invent new reductions"
);
for r in &log1.reductions {
let r3 = log3
.reductions
.iter()
.find(|x| x.id == r.id)
.unwrap_or_else(|| panic!("prior reduction {} vanished on re-projection", r.id));
assert_eq!(
r, r3,
"prior reduction {} churned across re-projection",
r.id
);
let msg1 = &view1[r.ptr.addr.index];
let msg3 = &view3[r.ptr.addr.index];
assert_eq!(
msg1.content, msg3.content,
"placeholder for {} changed byte-for-byte after appending messages",
r.id
);
}
}
#[test]
fn project_never_orphans_tool_pairs() {
let policies = [
ReductionPolicy::default(),
forcing_policy(),
ReductionPolicy {
tool_output_keep_bytes: 0,
tool_output_trigger_bytes: 0,
protect_last_n_tool_results: 1,
..ReductionPolicy::default()
},
ReductionPolicy {
tool_output_keep_bytes: 10,
tool_output_trigger_bytes: 20,
protect_last_n_tool_results: 3,
..ReductionPolicy::default()
},
];
for fixture_name in ["codex_session.jsonl", "claude_code_session.jsonl"] {
let mut session = if fixture_name == "codex_session.jsonl" {
load_codex()
} else {
load_claude()
};
pad_tool_output(&mut session, 0, 60_000);
for policy in &policies {
let (view, _log) = project(&session, policy, &ReductionLog::default());
for (i, msg) in view.iter().enumerate() {
for call in msg.tool_calls() {
if call.id.is_empty() {
continue;
}
let has_pair = view[i + 1..].iter().any(|m| {
m.role == Role::Tool && m.tool_call_id.as_deref() == Some(call.id.as_str())
});
assert!(
has_pair,
"{fixture_name}: tool_calls id {} at message {i} has no following tool \
result under policy {policy:?}",
call.id
);
}
}
}
}
}
#[test]
fn invert_project_is_identity() {
for fixture_name in ["codex", "claude"] {
let mut base = if fixture_name == "codex" {
load_codex()
} else {
load_claude()
};
pad_tool_output(&mut base, 0, 50_000);
base.messages.push(ChatMessage::user_with_images(
"check this out",
&[big_data_url("image/png", 20_000)],
));
let policy = forcing_policy();
let (view, log) = project(&base, &policy, &ReductionLog::default());
assert!(
!log.reductions.is_empty(),
"{fixture_name}: expected at least one reduction with the forcing policy"
);
assert!(
log.reductions
.iter()
.any(|r| matches!(r.kind, ReductionKind::ImageRedacted { .. })),
"{fixture_name}: expected an ImageRedacted reduction for the appended image message"
);
let inverted = invert(&view, &log, &base).unwrap();
assert_identity(
&format!("{fixture_name} fresh log"),
&inverted,
&base.messages,
);
let mut grown = base.clone();
append_synthetic_turns(&mut grown, 2);
let (view2, log2) = project(&grown, &policy, &log);
let inverted2 = invert(&view2, &log2, &grown).unwrap();
assert_identity(
&format!("{fixture_name} incremental log"),
&inverted2,
&grown.messages,
);
}
}
struct Lcg(u64);
impl Lcg {
fn next_u64(&mut self) -> u64 {
self.0 = self
.0
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
self.0
}
fn range(&mut self, lo: u64, hi_inclusive: u64) -> u64 {
lo + self.next_u64() % (hi_inclusive - lo + 1)
}
}
#[test]
fn invert_project_is_identity_property_stress() {
let mut base = load_codex();
pad_tool_output(&mut base, 0, 80_000);
if tool_indices(&base).len() > 1 {
pad_tool_output(&mut base, 1, 30_000);
}
base.messages.push(ChatMessage::user_with_images(
"photo",
&[big_data_url("image/jpeg", 50_000)],
));
let mut rng = Lcg(0x9E3779B97F4A7C15);
for iter in 0..200 {
let policy = ReductionPolicy {
tool_output_keep_bytes: rng.range(0, 100_000) as usize,
tool_output_trigger_bytes: rng.range(0, 100_000) as usize,
protect_last_n_tool_results: rng.range(0, 4) as usize,
..ReductionPolicy::default()
};
let (view, log) = project(&base, &policy, &ReductionLog::default());
let inverted = invert(&view, &log, &base).unwrap_or_else(|e| {
panic!("iteration {iter} with policy {policy:?} failed to invert: {e}")
});
assert_identity(
&format!("property stress iteration {iter} (policy {policy:?})"),
&inverted,
&base.messages,
);
}
}
#[test]
fn invert_errors_on_deleted_log_entry() {
let mut base = load_codex();
pad_tool_output(&mut base, 0, 50_000);
let policy = forcing_policy();
let (view, log) = project(&base, &policy, &ReductionLog::default());
assert!(!log.reductions.is_empty());
let mut tampered_log = log.clone();
tampered_log.reductions.remove(0);
let result = invert(&view, &tampered_log, &base);
assert!(
result.is_err(),
"invert() should fail loudly when a reduction record is missing from the log, not \
silently reproduce partial content"
);
}
#[test]
fn invert_errors_on_tampered_sidecar_content() {
let mut base = load_codex();
pad_tool_output(&mut base, 0, 50_000);
let policy = forcing_policy();
let (view, log) = project(&base, &policy, &ReductionLog::default());
assert!(!log.reductions.is_empty());
let first = &log.reductions[0];
let mut tampered = base.clone();
let idx = first.ptr.addr.index;
let mut content = tampered.messages[idx].content.clone().unwrap_or_default();
content.push('X'); tampered.messages[idx].content = Some(content);
let result = invert(&view, &log, &tampered);
assert!(
result.is_err(),
"invert() should fail loudly (hash mismatch) against a tampered sidecar, never \
substitute the wrong content"
);
}
#[test]
fn invert_one_restores_exactly_one_record() {
let mut base = load_codex();
pad_tool_output(&mut base, 0, 80_000);
if tool_indices(&base).len() > 1 {
pad_tool_output(&mut base, 1, 40_000);
}
let policy = forcing_policy();
let (view, log) = project(&base, &policy, &ReductionLog::default());
assert!(
log.reductions.len() >= 2,
"need at least 2 reductions for this test to be meaningful (got {})",
log.reductions.len()
);
let target = &log.reductions[0];
let target_id = target.id.clone();
let target_idx = target.ptr.addr.index;
let other = &log.reductions[1];
let other_idx = other.ptr.addr.index;
let other_content_before = view[other_idx].content.clone();
let (expanded, new_log) = invert_one(&view, &log, &target_id, &base).unwrap();
let expected_original = base.messages[target_idx].content.clone();
assert_eq!(
expanded[target_idx].content, expected_original,
"invert_one did not restore the targeted reduction's exact original content"
);
assert!(
reduction_id(&expanded[target_idx]).is_none(),
"invert_one should strip the sc.reduction metadata key from the expanded message"
);
assert_eq!(
expanded[other_idx].content, other_content_before,
"invert_one must not touch other reductions' placeholders"
);
assert!(
!new_log.reductions.iter().any(|r| r.id == target_id),
"invert_one's returned log should no longer contain the expanded record"
);
assert_eq!(new_log.reductions.len(), log.reductions.len() - 1);
}
fn empty_session() -> Session {
Session::from_claude_code_str("").unwrap()
}
#[test]
fn turns_cleared_is_deterministic_prefix_stable_and_invertible() {
let mut session = empty_session();
append_synthetic_turns(&mut session, 10);
let policy = ReductionPolicy {
clear_turns_older_than: Some(8),
..ReductionPolicy::default()
};
let prior = ReductionLog::default();
let (view1, log1) = project(&session, &policy, &prior);
let (view2, log2) = project(&session, &policy, &prior);
assert!(
messages_identical(&view1, &view2),
"project() is not deterministic for TurnsCleared"
);
assert_eq!(log1, log2);
assert_eq!(log1.reductions.len(), 1);
let r = &log1.reductions[0];
let (first, last) = match r.kind {
ReductionKind::TurnsCleared { first, last, .. } => (first, last),
ref other => panic!("expected TurnsCleared, got {other:?}"),
};
assert_eq!(first, 0, "clearing starts from the oldest message");
assert!(last >= first);
assert_eq!(r.ptr.span, None, "TurnsCleared pointers carry no byte span");
assert!(r.placeholder.contains("turns-cleared"), "{}", r.placeholder);
assert!(r.placeholder.contains(&r.id), "{}", r.placeholder);
assert_eq!(
view1.len(),
session.messages.len() - (last - first + 1) + 1,
"the cleared range collapses to exactly one placeholder message"
);
let placeholder_msg = &view1[first];
assert_eq!(placeholder_msg.role, Role::System);
assert_eq!(reduction_id(placeholder_msg), Some(r.id.as_str()));
let mut grown = session.clone();
append_synthetic_turns(&mut grown, 4);
let (view3, log3) = project(&grown, &policy, &log1);
assert_eq!(
log3.reductions.len(),
1,
"TurnsCleared is a singleton reduction: further growth must not create a second one"
);
assert_eq!(
log3.reductions[0], log1.reductions[0],
"the established TurnsCleared reduction must reproduce verbatim"
);
assert_eq!(
view1[first].content, view3[first].content,
"the placeholder's byte content must not churn across re-projection"
);
let inverted = invert(&view1, &log1, &session).unwrap();
assert_identity("turns-cleared", &inverted, &session.messages);
}
#[test]
fn turns_cleared_never_crosses_the_protected_imported_prefix() {
let mut session = empty_session();
append_synthetic_turns(&mut session, 10);
let policy = ReductionPolicy {
clear_turns_older_than: Some(8),
protect_imported_prefix: Some(12),
..ReductionPolicy::default()
};
let prior = ReductionLog::default();
let (view, log) = project(&session, &policy, &prior);
assert_eq!(
log.reductions.len(),
1,
"clearing must still occur beyond the protected prefix"
);
let (first, last) = match log.reductions[0].kind {
ReductionKind::TurnsCleared { first, last, .. } => (first, last),
ref other => panic!("expected TurnsCleared, got {other:?}"),
};
assert!(
first >= 12,
"clear range must never start inside the protected imported prefix: first={first}"
);
assert!(last >= first);
for (i, original) in session.messages.iter().take(12).enumerate() {
assert_eq!(
view[i].content, original.content,
"protected message {i} must be untouched"
);
assert_eq!(
reduction_id(&view[i]),
None,
"protected message {i} must carry no reduction"
);
}
let too_wide_policy = ReductionPolicy {
clear_turns_older_than: Some(8),
protect_imported_prefix: Some(session.messages.len()), ..ReductionPolicy::default()
};
let (view_none, log_none) = project(&session, &too_wide_policy, &ReductionLog::default());
assert!(
log_none.reductions.is_empty(),
"no room beyond a full-session protection: clearing must not happen at all"
);
assert_eq!(view_none.len(), session.messages.len());
}
fn a8_temp_dir(tag: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!("supercode-a8-{tag}-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn read_call(id: &str, path: &Path) -> ChatMessage {
ChatMessage {
role: Role::Assistant,
content: None,
content_parts: None,
tool_calls: Some(vec![ToolCall {
id: id.to_string(),
kind: "function".to_string(),
function: FunctionCall {
name: "read_file".to_string(),
arguments: serde_json::json!({ "path": path.to_string_lossy() }).to_string(),
},
}]),
tool_call_id: None,
name: None,
metadata: Default::default(),
}
}
fn eight_kb_content() -> String {
(0..8192).map(|i| (b'a' + (i % 26) as u8) as char).collect()
}
fn session_of(msgs: Vec<ChatMessage>) -> Session {
let mut session = empty_session();
session.messages = msgs;
session
}
#[test]
fn stale_read_elided_fresh_read_kept() {
let dir = a8_temp_dir("stale-read");
let file_path = dir.join("f.txt");
let original_content = eight_kb_content();
std::fs::write(&file_path, &original_content).unwrap();
let mut msgs = vec![
ChatMessage::user("please read the file"),
read_call("call_1", &file_path),
ChatMessage::tool_result("call_1", "read_file", original_content.clone()),
];
for i in 0..2 {
msgs.push(ChatMessage::user(format!("filler {i}")));
msgs.push(ChatMessage::assistant(format!("filler reply {i}")));
}
let read_idx = 2;
let policy = ReductionPolicy {
elide_stale_reads: true,
protect_last_n_tool_results: 0,
..ReductionPolicy::default()
};
let freshness = probe_read_freshness(&msgs);
let policy_with_fresh = ReductionPolicy {
read_freshness: freshness,
..policy.clone()
};
let (view, log) = project_messages(&msgs, &policy_with_fresh, &ReductionLog::default());
assert_eq!(
log.reductions.len(),
1,
"the fresh read should have produced exactly one reduction"
);
let r = &log.reductions[0];
match &r.kind {
ReductionKind::FileReadElided { path, read_log } => {
assert_eq!(path, &file_path);
assert_eq!(read_log.path, file_path);
assert_eq!(read_log.addr.index, read_idx);
assert_eq!(read_log.content_hash, r.ptr.content_hash);
}
other => panic!("expected FileReadElided, got {other:?}"),
}
assert_eq!(r.ptr.span, None, "whole-content elision carries no span");
let placeholder = view[read_idx].content.clone().unwrap();
assert!(
placeholder.contains("file-read"),
"placeholder should use the file-read stub kind: {placeholder}"
);
assert!(
placeholder.contains(&file_path.to_string_lossy().to_string()),
"placeholder should name the read path: {placeholder}"
);
assert!(
placeholder.contains("unchanged on disk"),
"placeholder should explain why it was elided: {placeholder}"
);
assert_eq!(reduction_id(&view[read_idx]), Some(r.id.as_str()));
assert_eq!(
log.read_log.len(),
1,
"every detected read appends to the read-log, elided or not"
);
assert_eq!(log.read_log[0].path, file_path);
assert_eq!(log.read_log[0].addr.index, read_idx);
let sidecar = session_of(msgs.clone());
let inverted = invert(&view, &log, &sidecar).unwrap();
assert_eq!(
inverted[read_idx].content.as_deref(),
Some(original_content.as_str()),
"invert must restore the original 8KB content exactly"
);
assert_identity("stale-read fresh case", &inverted, &msgs);
let mut grown = msgs.clone();
grown.push(read_call("call_2", &file_path));
grown.push(ChatMessage::tool_result(
"call_2",
"read_file",
original_content.clone(),
));
let second_read_idx = grown.len() - 1;
let modified_content = format!("{original_content}-modified-on-disk");
std::fs::write(&file_path, &modified_content).unwrap();
let freshness2 = probe_read_freshness(&grown);
let policy2 = ReductionPolicy {
read_freshness: freshness2,
..policy.clone()
};
let (view2, log2) = project_messages(&grown, &policy2, &log);
assert_eq!(
view2[read_idx].content, view[read_idx].content,
"the previously-elided read must stay elided verbatim even though F changed"
);
let file_read_reductions: Vec<_> = log2
.reductions
.iter()
.filter(|r| matches!(r.kind, ReductionKind::FileReadElided { .. }))
.collect();
assert_eq!(
file_read_reductions.len(),
1,
"the changed file must not gain a NEW elision; only the original one survives"
);
assert_eq!(file_read_reductions[0], &log.reductions[0]);
assert_eq!(
view2[second_read_idx].content.as_deref(),
Some(original_content.as_str()),
"the second (now-stale) read must not be elided"
);
assert!(reduction_id(&view2[second_read_idx]).is_none());
assert_eq!(
log2.read_log.len(),
2,
"read-log should record both reads, deduplicated across re-projection"
);
assert_eq!(log2.read_log[0].addr.index, read_idx);
assert_eq!(log2.read_log[1].addr.index, second_read_idx);
assert_eq!(log2.read_log[1].path, file_path);
let sidecar2 = session_of(grown.clone());
let inverted2 = invert(&view2, &log2, &sidecar2).unwrap();
assert_identity("stale-read after on-disk modification", &inverted2, &grown);
let json = serde_json::to_string(&log2).unwrap();
let reloaded: ReductionLog = serde_json::from_str(&json).unwrap();
assert_eq!(reloaded, log2, "ReductionLog must serde round-trip exactly");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn stale_read_unreadable_file_not_elided() {
let dir = a8_temp_dir("unreadable");
let file_path = dir.join("gone.txt");
let content = eight_kb_content();
std::fs::write(&file_path, &content).unwrap();
let msgs = vec![
ChatMessage::user("please read the file"),
read_call("call_1", &file_path),
ChatMessage::tool_result("call_1", "read_file", content.clone()),
];
std::fs::remove_file(&file_path).unwrap();
let freshness = probe_read_freshness(&msgs);
let policy = ReductionPolicy {
elide_stale_reads: true,
protect_last_n_tool_results: 0,
read_freshness: freshness,
..ReductionPolicy::default()
};
let (view, log) = project_messages(&msgs, &policy, &ReductionLog::default());
assert!(
log.reductions.is_empty(),
"an unreadable/deleted file must never be elided"
);
assert_eq!(
log.read_log.len(),
1,
"the read is still recorded in the read-log even though it wasn't elided"
);
assert_eq!(view[2].content.as_deref(), Some(content.as_str()));
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn image_redaction_data_url_threshold_mime_and_reversible() {
let big = big_data_url("image/png", 20_000); let small = big_data_url("image/gif", 100); let remote = "https://example.com/photo.jpg".to_string();
let msgs = vec![
ChatMessage::user("hello"),
ChatMessage::user_with_images("look", &[big.clone(), small.clone(), remote.clone()]),
];
let policy = ReductionPolicy::default(); let (view, log) = project_messages(&msgs, &policy, &ReductionLog::default());
assert_eq!(
log.reductions.len(),
1,
"only the over-threshold data: URL should become a candidate"
);
let r = &log.reductions[0];
let part_index = match r.kind {
ReductionKind::ImageRedacted { part_index } => part_index,
ref other => panic!("expected ImageRedacted, got {other:?}"),
};
assert_eq!(
part_index, 1,
"the big image is content_parts[1] (after the caption text)"
);
assert_eq!(
r.ptr.span, None,
"whole-part redaction carries no byte span"
);
let parts = view[1].content_parts.as_ref().unwrap();
assert_eq!(
parts.len(),
4,
"redaction replaces a part in place; it never changes the part count"
);
assert_eq!(parts[0]["type"], "text");
assert_eq!(parts[0]["text"], "look");
assert_eq!(parts[1]["type"], "text");
let stub_text = parts[1]["text"].as_str().unwrap();
assert!(stub_text.starts_with(REDUCTION_SENTINEL), "{stub_text}");
assert!(stub_text.contains("image/png"), "{stub_text}");
assert!(stub_text.contains("KB)"), "{stub_text}");
assert_eq!(stub_text, r.placeholder);
assert_eq!(reduction_id(&view[1]), Some(r.id.as_str()));
assert_eq!(parts[2]["image_url"]["url"], small);
assert_eq!(parts[3]["image_url"]["url"], remote);
let body = serde_json::to_string(&view).unwrap();
assert!(
!body.contains("data:image/png"),
"the redacted image's bytes must not reach the wire: {body}"
);
let sidecar = session_of(msgs.clone());
let inverted = invert(&view, &log, &sidecar).unwrap();
assert_eq!(inverted[1].content_parts, msgs[1].content_parts);
assert_identity("image redaction", &inverted, &msgs);
let (view2, log2) = project_messages(&msgs, &policy, &log);
assert_eq!(log2, log);
assert_eq!(view2[1].content_parts, view[1].content_parts);
}
#[test]
fn image_redaction_is_noop_on_image_free_fixtures() {
for (label, session) in [("codex", load_codex()), ("claude", load_claude())] {
let policy = ReductionPolicy {
redact_images: true,
..ReductionPolicy::default()
};
let before_count = session.messages.len();
let (view, log) = project(&session, &policy, &ReductionLog::default());
assert_eq!(
view.len(),
before_count,
"{label}: redact_images must be a no-op on message count for an image-free fixture"
);
assert!(
log.reductions
.iter()
.all(|r| !matches!(r.kind, ReductionKind::ImageRedacted { .. })),
"{label}: an image-free fixture must never produce an ImageRedacted record"
);
}
}
fn n_line_file(n: usize) -> String {
use std::fmt::Write;
let mut out = String::with_capacity(n * 10);
for i in 0..n {
writeln!(out, "line {i:04}").unwrap();
}
out
}
fn edit_lines(content: &str, from: usize, len: usize) -> String {
let mut out = String::with_capacity(content.len());
for (i, line) in content.lines().enumerate() {
if i >= from && i < from + len {
out.push_str(&format!("CHANGED {i}"));
} else {
out.push_str(line);
}
out.push('\n');
}
out
}
fn tr3_policy() -> ReductionPolicy {
ReductionPolicy {
tool_output_trigger_bytes: usize::MAX,
protect_last_n_tool_results: 0,
..ReductionPolicy::default()
}
}
#[test]
fn dev01_dev02_small_edit_re_read_diffs_and_invert_and_patch_apply() {
let file_path = PathBuf::from("/workspace/src/foo.rs");
let base_content = n_line_file(2000);
let new_content = edit_lines(&base_content, 1000, 3);
assert_ne!(base_content, new_content);
let msgs = vec![
ChatMessage::user("read the file"),
read_call("c1", &file_path),
ChatMessage::tool_result("c1", "read_file", base_content.clone()),
ChatMessage::user("make a small edit"),
ChatMessage::assistant("done"),
read_call("c2", &file_path),
ChatMessage::tool_result("c2", "read_file", new_content.clone()),
];
let base_idx = 2;
let new_idx = 6;
let policy = tr3_policy();
let (view, log) = project_messages(&msgs, &policy, &ReductionLog::default());
assert_eq!(
log.reductions.len(),
1,
"only the re-read should produce a reduction; the base read stays untouched: {log:#?}"
);
let r = &log.reductions[0];
let (path, base, base_hash, new_hash, original_bytes, diff_bytes) = match &r.kind {
ReductionKind::FileReadDiffed {
path,
base,
base_hash,
new_hash,
original_bytes,
diff_bytes,
} => (
path.clone(),
*base,
base_hash.clone(),
new_hash.clone(),
*original_bytes,
*diff_bytes,
),
other => panic!("expected FileReadDiffed, got {other:?}"),
};
assert_eq!(path, file_path);
assert_eq!(base.index, base_idx);
assert_eq!(base_hash, content_hash(base_content.as_bytes()));
assert_eq!(new_hash, content_hash(new_content.as_bytes()));
assert_eq!(original_bytes, new_content.len());
assert_eq!(r.ptr.content_hash, new_hash);
assert_eq!(
r.ptr.span, None,
"whole-content replacement carries no span"
);
assert_eq!(r.ptr.addr.index, new_idx);
assert!(
(diff_bytes as f64) <= (original_bytes as f64) * 0.10,
"expected the diff to be a small fraction of the full content: {diff_bytes} / {original_bytes}"
);
let placeholder = view[new_idx].content.clone().unwrap();
assert!(placeholder.starts_with(REDUCTION_SENTINEL));
assert!(placeholder.contains("file-read-diffed"));
assert_eq!(reduction_id(&view[new_idx]), Some(r.id.as_str()));
assert!(
placeholder.len() <= new_content.len() / 2,
"projected bytes must be <= 50% of the full re-read: {} vs {}",
placeholder.len(),
new_content.len()
);
let stub_line_end = placeholder.find('\n').expect("stub line then diff text");
let diff_text = &placeholder[stub_line_end + 1..];
let patch = diffy::Patch::from_str(diff_text).expect("projected diff must parse");
let applied = diffy::apply(&base_content, &patch).expect("projected diff must apply cleanly");
assert_eq!(
applied, new_content,
"patch-apply must reproduce the new content exactly"
);
let sidecar = session_of(msgs.clone());
let inverted = invert(&view, &log, &sidecar).unwrap();
assert_eq!(
inverted[new_idx].content.as_deref(),
Some(new_content.as_str())
);
assert_identity("TR-3 small-edit re-read", &inverted, &msgs);
let (view2, log2) = project_messages(&msgs, &policy, &log);
assert_eq!(log2, log);
assert_eq!(view2[new_idx].content, view[new_idx].content);
}
#[test]
fn dev03_large_change_guard_keeps_full_re_read() {
let file_path = PathBuf::from("/workspace/src/rewrite.rs");
let base_content = eight_kb_content(); let new_content: String = (0..base_content.len())
.map(|i| (b'0' + (i % 10) as u8) as char)
.collect();
let msgs = vec![
ChatMessage::user("read the file"),
read_call("c1", &file_path),
ChatMessage::tool_result("c1", "read_file", base_content.clone()),
ChatMessage::user("rewrite it completely"),
ChatMessage::assistant("done"),
read_call("c2", &file_path),
ChatMessage::tool_result("c2", "read_file", new_content.clone()),
];
let new_idx = 6;
let policy = tr3_policy();
let (view, log) = project_messages(&msgs, &policy, &ReductionLog::default());
assert!(
log.reductions.is_empty(),
"a full rewrite must produce NO reduction at all (guard tripped): {log:#?}"
);
assert_eq!(
view[new_idx].content.as_deref(),
Some(new_content.as_str()),
"the full re-read must stay untouched when the diff is too large to compress usefully"
);
assert!(reduction_id(&view[new_idx]).is_none());
assert_eq!(
log.read_log.len(),
2,
"both reads are still recorded in the read-log even though neither was reduced"
);
}
#[test]
fn dev04_chained_re_reads_never_compound_diffs() {
let file_path = PathBuf::from("/workspace/src/chain.rs");
let v1 = n_line_file(500);
let v2 = edit_lines(&v1, 100, 2); let v3 = edit_lines(&v2, 300, 2);
let msgs = vec![
ChatMessage::user("read"),
read_call("c1", &file_path),
ChatMessage::tool_result("c1", "read_file", v1.clone()),
ChatMessage::user("edit A"),
ChatMessage::assistant("done"),
read_call("c2", &file_path),
ChatMessage::tool_result("c2", "read_file", v2.clone()),
ChatMessage::user("edit B"),
ChatMessage::assistant("done"),
read_call("c3", &file_path),
ChatMessage::tool_result("c3", "read_file", v3.clone()),
];
let idx1 = 2;
let idx2 = 6;
let idx3 = 10;
let policy = tr3_policy();
let (view, log) = project_messages(&msgs, &policy, &ReductionLog::default());
assert_eq!(
log.reductions.len(),
2,
"read1 has no prior read to diff against; read2 and read3 each diff: {log:#?}"
);
let r2 = log
.reductions
.iter()
.find(|r| r.ptr.addr.index == idx2)
.expect("read2's reduction");
let r3 = log
.reductions
.iter()
.find(|r| r.ptr.addr.index == idx3)
.expect("read3's reduction");
match &r2.kind {
ReductionKind::FileReadDiffed {
base, base_hash, ..
} => {
assert_eq!(base.index, idx1, "read2's base must be read1");
assert_eq!(base_hash, &content_hash(v1.as_bytes()));
}
other => panic!("expected FileReadDiffed for read2, got {other:?}"),
}
match &r3.kind {
ReductionKind::FileReadDiffed {
base, base_hash, ..
} => {
assert_eq!(
base.index, idx2,
"read3's base must be read2 (its ORIGINAL bytes) -- never read1, and never a diff-of-diff"
);
assert_eq!(base_hash, &content_hash(v2.as_bytes()));
}
other => panic!("expected FileReadDiffed for read3, got {other:?}"),
}
let placeholder3 = view[idx3].content.clone().unwrap();
let diff_text3 = &placeholder3[placeholder3.find('\n').unwrap() + 1..];
let patch3 = diffy::Patch::from_str(diff_text3).unwrap();
let applied3 = diffy::apply(&v2, &patch3).unwrap();
assert_eq!(applied3, v3);
let sidecar = session_of(msgs.clone());
let inverted = invert(&view, &log, &sidecar).unwrap();
assert_eq!(inverted[idx2].content.as_deref(), Some(v2.as_str()));
assert_eq!(inverted[idx3].content.as_deref(), Some(v3.as_str()));
assert_identity("TR-3 chained re-reads", &inverted, &msgs);
}
#[test]
fn dev05_a8_vs_tr3_precedence_by_case() {
let dir_a = a8_temp_dir("tr3-precedence-unchanged");
let path_a = dir_a.join("f.txt");
let content_a = eight_kb_content();
std::fs::write(&path_a, &content_a).unwrap();
let msgs_a = vec![
ChatMessage::user("read"),
read_call("ca1", &path_a),
ChatMessage::tool_result("ca1", "read_file", content_a.clone()),
ChatMessage::user("read again"),
read_call("ca2", &path_a),
ChatMessage::tool_result("ca2", "read_file", content_a.clone()),
];
let idx_a2 = 5;
let freshness_a = probe_read_freshness(&msgs_a);
let policy_a = ReductionPolicy {
elide_stale_reads: true,
diff_rereads: true,
protect_last_n_tool_results: 0,
tool_output_trigger_bytes: usize::MAX,
read_freshness: freshness_a,
..ReductionPolicy::default()
};
let (_, log_a) = project_messages(&msgs_a, &policy_a, &ReductionLog::default());
let r_a2 = log_a
.reductions
.iter()
.find(|r| r.ptr.addr.index == idx_a2)
.expect("the unchanged re-read must be reduced");
assert!(
matches!(r_a2.kind, ReductionKind::FileReadElided { .. }),
"an unchanged re-read must take the A8 elision path, not a zero-hunk diff: {:?}",
r_a2.kind
);
std::fs::remove_dir_all(&dir_a).ok();
let dir_b = a8_temp_dir("tr3-precedence-changed");
let path_b = dir_b.join("f.txt");
let content_b1 = n_line_file(500);
let content_b2 = edit_lines(&content_b1, 250, 2);
std::fs::write(&path_b, &content_b1).unwrap();
let msgs_b = vec![
ChatMessage::user("read"),
read_call("cb1", &path_b),
ChatMessage::tool_result("cb1", "read_file", content_b1.clone()),
ChatMessage::user("edit"),
ChatMessage::assistant("done"),
read_call("cb2", &path_b),
ChatMessage::tool_result("cb2", "read_file", content_b2.clone()),
];
let idx_b1 = 2;
let idx_b2 = 6;
std::fs::write(&path_b, &content_b2).unwrap();
let freshness_b = probe_read_freshness(&msgs_b);
let policy_b = ReductionPolicy {
elide_stale_reads: true,
diff_rereads: true,
protect_last_n_tool_results: 0,
tool_output_trigger_bytes: usize::MAX,
read_freshness: freshness_b,
..ReductionPolicy::default()
};
let (view_b, log_b) = project_messages(&msgs_b, &policy_b, &ReductionLog::default());
let r_b2 = log_b
.reductions
.iter()
.find(|r| r.ptr.addr.index == idx_b2)
.expect("the changed re-read must be reduced");
assert!(
matches!(r_b2.kind, ReductionKind::FileReadDiffed { .. }),
"a changed re-read must take the TR-3 diff path even when A8 also considers it fresh: {:?}",
r_b2.kind
);
assert!(reduction_id(&view_b[idx_b1]).is_none());
std::fs::remove_dir_all(&dir_b).ok();
}
fn read_call_windowed(id: &str, path: &Path, offset: usize, limit: usize) -> ChatMessage {
ChatMessage {
role: Role::Assistant,
content: None,
content_parts: None,
tool_calls: Some(vec![ToolCall {
id: id.to_string(),
kind: "function".to_string(),
function: FunctionCall {
name: "read_file".to_string(),
arguments: serde_json::json!({
"path": path.to_string_lossy(),
"offset": offset,
"limit": limit,
})
.to_string(),
},
}]),
tool_call_id: None,
name: None,
metadata: Default::default(),
}
}
#[test]
fn windowed_re_read_never_mints_file_read_diffed() {
let file_path = PathBuf::from("/workspace/src/windowed.rs");
let base_content = n_line_file(200);
let new_content = edit_lines(&base_content, 50, 2);
let msgs = vec![
ChatMessage::user("read a slice of the file"),
read_call_windowed("c1", &file_path, 1, 100),
ChatMessage::tool_result("c1", "read_file", base_content.clone()),
ChatMessage::user("read a different slice"),
read_call_windowed("c2", &file_path, 50, 100),
ChatMessage::tool_result("c2", "read_file", new_content.clone()),
];
let idx1 = 2;
let idx2 = 5;
let policy = tr3_policy();
let (view, log) = project_messages(&msgs, &policy, &ReductionLog::default());
assert!(
!log.reductions
.iter()
.any(|r| matches!(r.kind, ReductionKind::FileReadDiffed { .. })),
"a partial-window re-read must never mint FileReadDiffed: {:?}",
log.reductions
);
assert_eq!(view[idx1].content.as_deref(), Some(base_content.as_str()));
assert_eq!(view[idx2].content.as_deref(), Some(new_content.as_str()));
assert!(reduction_id(&view[idx1]).is_none());
assert!(reduction_id(&view[idx2]).is_none());
}