use supercode::reduce::{
project_messages, tool_outcome, ReductionKind, ReductionLog, ReductionPolicy, ToolOutcome,
};
use supercode::{ChatMessage, Role, Session, SessionFormat};
fn filler(len: usize) -> String {
(0..len).map(|i| (b'a' + (i % 26) as u8) as char).collect()
}
fn codex_session(output_kind: &str, output: &str) -> Session {
let payload = filler(20_000);
let call_kind = match output_kind {
"function_call_output" => "function_call",
"custom_tool_call_output" => "custom_tool_call",
other => panic!("unsupported output kind {other}"),
};
let call_payload = if call_kind == "function_call" {
serde_json::json!({
"type": call_kind,
"call_id": "c1",
"name": "mcp__blobstore__put",
"arguments": serde_json::json!({"key":"asset/1", "data": payload}).to_string()
})
} else {
serde_json::json!({
"type": call_kind,
"call_id": "c1",
"name": "mcp__blobstore__put",
"input": {"key":"asset/1", "data": payload}
})
};
let jsonl = [
serde_json::json!({"type":"response_item", "payload": call_payload}),
serde_json::json!({
"type":"response_item",
"payload":{"type":output_kind, "call_id":"c1", "output":output}
}),
]
.into_iter()
.map(|record| serde_json::to_string(&record).unwrap())
.collect::<Vec<_>>()
.join("\n")
+ "\n";
Session::from_codex_str(&jsonl).unwrap()
}
fn opted_in_policy() -> ReductionPolicy {
let mut policy = ReductionPolicy::default();
policy
.tool_input_elidable_fields
.insert("mcp__blobstore__put".to_string(), "data".to_string());
policy
}
fn assert_no_tool_input_reduction(log: &ReductionLog) {
assert!(
!log.reductions
.iter()
.any(|r| matches!(r.kind, ReductionKind::ToolInputElided { .. })),
"unknown Codex outcome must fail closed on both input-reduction paths: {:?}",
log.reductions
);
}
#[test]
fn codex_failed_output_is_neither_tr10_elided_nor_tr6_pruned() {
let session = codex_session("function_call_output", "Process exited with code 1");
assert_eq!(session.messages.len(), 2);
assert_eq!(tool_outcome(&session.messages[1]), ToolOutcome::Unknown);
let mut tr10_policy = opted_in_policy();
tr10_policy.prune_errored_inputs = false;
let (tr10_view, tr10_log) =
project_messages(&session.messages, &tr10_policy, &ReductionLog::default());
assert_no_tool_input_reduction(&tr10_log);
assert_eq!(
tr10_view[0].tool_calls()[0].function.arguments,
session.messages[0].tool_calls()[0].function.arguments
);
let mut tr6_policy = opted_in_policy();
tr6_policy.elide_tool_inputs = false;
tr6_policy.prune_errored_inputs = true;
tr6_policy.errored_input_prune_after_turns = 0;
let (tr6_view, tr6_log) =
project_messages(&session.messages, &tr6_policy, &ReductionLog::default());
assert_no_tool_input_reduction(&tr6_log);
assert_eq!(
tr6_view[0].tool_calls()[0].function.arguments,
session.messages[0].tool_calls()[0].function.arguments
);
}
#[test]
fn codex_custom_output_is_also_explicitly_unknown() {
let session = codex_session("custom_tool_call_output", "tool reported failure");
assert_eq!(tool_outcome(&session.messages[1]), ToolOutcome::Unknown);
let (_, log) = project_messages(
&session.messages,
&opted_in_policy(),
&ReductionLog::default(),
);
assert_no_tool_input_reduction(&log);
}
#[test]
fn claude_omitted_is_error_and_live_success_remain_known_success() {
let payload = filler(20_000);
let claude = format!(
"{{\"type\":\"assistant\",\"uuid\":\"a1\",\"sessionId\":\"s\",\"message\":{{\"id\":\"m1\",\"role\":\"assistant\",\"content\":[{{\"type\":\"tool_use\",\"id\":\"c1\",\"name\":\"mcp__blobstore__put\",\"input\":{{\"key\":\"asset/1\",\"data\":{payload:?}}}}}]}}}}\n{{\"type\":\"user\",\"uuid\":\"u1\",\"parentUuid\":\"a1\",\"sessionId\":\"s\",\"message\":{{\"role\":\"user\",\"content\":[{{\"type\":\"tool_result\",\"tool_use_id\":\"c1\",\"content\":\"ok\"}}]}}}}\n"
);
let imported = Session::from_claude_code_str(&claude).unwrap();
let claude_result = imported
.messages
.iter()
.find(|message| message.role == Role::Tool)
.expect("Claude tool result");
assert_eq!(tool_outcome(claude_result), ToolOutcome::KnownSuccess);
let (_, claude_log) = project_messages(
&imported.messages,
&opted_in_policy(),
&ReductionLog::default(),
);
assert!(claude_log
.reductions
.iter()
.any(|r| matches!(r.kind, ReductionKind::ToolInputElided { .. })));
let live_call = imported
.messages
.iter()
.find(|message| message.role == Role::Assistant)
.expect("Claude tool call")
.clone();
let live_result = ChatMessage::tool_result("c1", "mcp__blobstore__put", "ok");
assert_eq!(tool_outcome(&live_result), ToolOutcome::KnownSuccess);
let (_, live_log) = project_messages(
&[live_call, live_result],
&opted_in_policy(),
&ReductionLog::default(),
);
assert!(live_log
.reductions
.iter()
.any(|r| matches!(r.kind, ReductionKind::ToolInputElided { .. })));
}
#[test]
fn codex_unknown_outcome_survives_native_sidecar_disk_round_trip() {
let imported = codex_session("function_call_output", "Process exited with code 1");
let empty = Session::from_codex_str("").unwrap();
let native = empty.to_native_jsonl_v2(&imported.messages);
assert!(
native.contains("sc.tool_outcome_unknown"),
"the appended NativeTurn must persist the explicit marker, not merely re-derive it from a raw Codex prefix"
);
let dir = std::env::temp_dir().join(format!(
"supercode-tr13-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("session.sidecar.jsonl");
std::fs::write(&path, native).unwrap();
let reloaded = Session::from_native_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
let result = reloaded
.messages
.iter()
.find(|message| message.role == Role::Tool)
.expect("reloaded Codex tool result");
assert_eq!(tool_outcome(result), ToolOutcome::Unknown);
std::fs::remove_dir_all(dir).ok();
}
#[test]
fn codex_unknown_outcome_survives_claude_translation_round_trip() {
let imported = codex_session("function_call_output", "Process exited with code 1");
let claude = imported.to_jsonl(SessionFormat::ClaudeCode).unwrap();
assert!(claude.contains("_supercode_tool_outcome"));
let reloaded = Session::from_claude_code_str(&claude).unwrap();
let result = reloaded
.messages
.iter()
.find(|message| message.role == Role::Tool)
.expect("translated Claude tool result");
assert_eq!(tool_outcome(result), ToolOutcome::Unknown);
}
#[test]
fn codex_unknown_outcome_survives_every_format_and_onward_translation() {
for output_kind in ["function_call_output", "custom_tool_call_output"] {
let imported = codex_session(output_kind, "Process exited with code 1");
for format in [
SessionFormat::ClaudeCode,
SessionFormat::Codex,
SessionFormat::OpenCode,
SessionFormat::Pi,
SessionFormat::Grok,
] {
let exported = imported.to_jsonl(format).unwrap();
let reloaded = Session::load_str(&exported, format).unwrap();
let result = reloaded
.messages
.iter()
.find(|message| message.role == Role::Tool)
.unwrap_or_else(|| panic!("{output_kind} -> {format:?} dropped the tool result"));
assert_eq!(
tool_outcome(result),
ToolOutcome::Unknown,
"{output_kind} -> {format:?} upgraded unknown to a known outcome"
);
let mut policy = opted_in_policy();
policy.errored_input_prune_after_turns = 0;
let (_, log) = project_messages(&reloaded.messages, &policy, &ReductionLog::default());
assert_no_tool_input_reduction(&log);
let onward = reloaded.to_jsonl(SessionFormat::ClaudeCode).unwrap();
let onward_reloaded = Session::from_claude_code_str(&onward).unwrap();
let onward_result = onward_reloaded
.messages
.iter()
.find(|message| message.role == Role::Tool)
.unwrap_or_else(|| {
panic!("{output_kind} -> {format:?} -> Claude dropped the tool result")
});
assert_eq!(
tool_outcome(onward_result),
ToolOutcome::Unknown,
"{output_kind} -> {format:?} -> Claude lost unknown"
);
}
}
}