use std::path::PathBuf;
use supercode::session::Session;
use supercode::Role;
#[test]
fn claude_tool_results_preserve_nontext_and_recover_from_tooluseresult() {
let image_only = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"t1","name":"Screenshot","input":{}}]},"sessionId":"s"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":[{"type":"image","source":{"type":"base64","data":"x"}}]}]},"sessionId":"s"}
"#;
let s = Session::from_claude_code_str(image_only).unwrap();
let tool = s.messages.iter().find(|m| m.role == Role::Tool).unwrap();
assert_eq!(
tool.content.as_deref(),
Some("[image]"),
"image-only result"
);
let ref_only = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"t2","name":"X","input":{}}]},"sessionId":"s"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t2","content":[{"type":"tool_reference","tool_name":"mcp__playwright__browser_navigate"}]}]},"sessionId":"s"}
"#;
let s = Session::from_claude_code_str(ref_only).unwrap();
let tool = s.messages.iter().find(|m| m.role == Role::Tool).unwrap();
assert!(
tool.content
.as_deref()
.unwrap_or("")
.contains("browser_navigate"),
"tool_reference name preserved"
);
let empty_with_tur = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"t3","name":"Edit","input":{}}]},"sessionId":"s"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t3","content":""}]},"toolUseResult":{"filePath":"/p/x.rs","oldString":"a","newString":"b"},"sessionId":"s"}
"#;
let s = Session::from_claude_code_str(empty_with_tur).unwrap();
let tool = s.messages.iter().find(|m| m.role == Role::Tool).unwrap();
let c = tool.content.as_deref().unwrap_or("");
assert!(
c.contains("x.rs") && c.contains("newString"),
"recovered from toolUseResult: {c}"
);
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn claude_empty_tool_results_recovered_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".claude/projects");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
let mut target: Option<String> = None;
for line in text.lines() {
let Ok(v) = serde_json::from_str::<serde_json::Value>(line) else {
continue;
};
if v.get("type").and_then(|x| x.as_str()) != Some("user")
|| v.get("toolUseResult").is_none()
{
continue;
}
let tr_text: String = v
.get("message")
.and_then(|m| m.get("content"))
.and_then(|c| c.as_array())
.map(|arr| {
arr.iter()
.filter(|b| b.get("type").and_then(|x| x.as_str()) == Some("tool_result"))
.map(|b| match b.get("content") {
Some(serde_json::Value::String(s)) => s.clone(),
Some(serde_json::Value::Array(a)) => a
.iter()
.filter_map(|i| i.get("text").and_then(|x| x.as_str()))
.collect::<Vec<_>>()
.join(""),
_ => String::new(),
})
.collect::<String>()
})
.unwrap_or_default();
if tr_text.trim().is_empty() {
target = v
.get("message")
.and_then(|m| m.get("content"))
.and_then(|c| c.as_array())
.and_then(|a| {
a.iter()
.find(|b| b.get("type").and_then(|x| x.as_str()) == Some("tool_result"))
})
.and_then(|b| b.get("tool_use_id"))
.and_then(|x| x.as_str())
.map(str::to_string);
if target.is_some() {
break;
}
}
}
let Some(tid) = target else { continue };
let s = Session::from_claude_code_str(&text).unwrap();
let tool = s
.messages
.iter()
.find(|m| m.role == Role::Tool && m.tool_call_id.as_deref() == Some(&tid));
if let Some(tool) = tool {
assert!(
!tool.content.as_deref().unwrap_or("").trim().is_empty(),
"{}: tool result {tid} still blank after recovery",
path.display()
);
proven = true;
eprintln!(
"proven on {}: previously-blank tool result now has content",
path.display()
);
break;
}
}
assert!(
proven,
"no Claude session with an empty tool_result + toolUseResult found"
);
}
#[test]
fn claude_content_attachments_are_folded_in() {
let jsonl = r#"
{"type":"user","message":{"role":"user","content":"start"},"sessionId":"s","cwd":"/tmp"}
{"type":"attachment","attachment":{"type":"queued_command","commandMode":"prompt","prompt":"QUEUED user prompt text"}}
{"type":"attachment","attachment":{"type":"file","filename":"/p/notes.md","content":"FILE BODY here"}}
{"type":"attachment","attachment":{"type":"edited_text_file","filename":"/p/edit.rs","snippet":"EDITED SNIPPET"}}
{"type":"attachment","attachment":{"type":"nested_memory","path":"/p/CLAUDE.md","content":"MEMORY CONTENT"}}
{"type":"attachment","attachment":{"type":"skill_listing","skills":["x"]}}
{"type":"attachment","attachment":{"type":"task_reminder","text":"noise"}}
"#;
let s = Session::from_claude_code_str(jsonl).unwrap();
let all: String = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect::<Vec<_>>()
.join("\n");
assert!(all.contains("QUEUED user prompt text"), "{all}");
assert!(
all.contains("FILE BODY here") && all.contains("notes.md"),
"{all}"
);
assert!(all.contains("EDITED SNIPPET"), "{all}");
assert!(all.contains("MEMORY CONTENT"), "{all}");
assert!(!all.contains("noise"), "{all}");
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn claude_attachments_recovered_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".claude/projects");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
if !text.contains("\"attachment\"") {
continue;
}
let mut needle: Option<String> = None;
for line in text.lines() {
let Ok(v) = serde_json::from_str::<serde_json::Value>(line) else {
continue;
};
if v.get("type").and_then(|x| x.as_str()) != Some("attachment") {
continue;
}
let Some(att) = v.get("attachment") else {
continue;
};
let body = match att.get("type").and_then(|x| x.as_str()) {
Some("queued_command") => att.get("prompt"),
Some("file") | Some("nested_memory") => att.get("content"),
Some("edited_text_file") => att.get("snippet"),
_ => None,
}
.and_then(|x| x.as_str());
if let Some(b) = body {
let snippet: String = b
.trim_start()
.chars()
.take_while(|c| !c.is_control())
.take(40)
.collect();
if snippet.trim().len() > 12 {
needle = Some(snippet.trim().to_string());
break;
}
}
}
let Some(needle) = needle else { continue };
let s = Session::from_claude_code_str(&text).unwrap();
let blob: String = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect();
assert!(
blob.contains(needle.trim()),
"{}: file attachment content not folded into the conversation",
path.display()
);
proven = true;
eprintln!(
"proven on {}: file attachment content now in conversation",
path.display()
);
break;
}
assert!(proven, "no Claude session with a file attachment found");
}
#[test]
fn codex_compacted_replaces_history() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"ORIGINAL long question one"}]}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"ORIGINAL long answer one"}]}}
{"type":"compacted","payload":{"message":"","replacement_history":[{"type":"message","role":"user","content":[{"type":"input_text","text":"SUMMARY of the conversation so far"}]}]}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"follow-up after compaction"}]}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let texts: Vec<String> = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect();
assert!(!texts.iter().any(|t| t.contains("ORIGINAL")), "{texts:?}");
assert!(texts.iter().any(|t| t.contains("SUMMARY")), "{texts:?}");
assert!(
texts
.iter()
.any(|t| t.contains("follow-up after compaction")),
"{texts:?}"
);
}
#[test]
fn codex_thread_rolled_back_drops_last_turn() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"keep me"}]}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"kept answer"}]}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"undo this turn"}]}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"answer to be undone"}]}}
{"type":"event_msg","payload":{"type":"thread_rolled_back","num_turns":1}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let texts: Vec<String> = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect();
assert!(texts.iter().any(|t| t.contains("keep me")), "{texts:?}");
assert!(texts.iter().any(|t| t.contains("kept answer")), "{texts:?}");
assert!(
!texts.iter().any(|t| t.contains("undo this turn")),
"{texts:?}"
);
assert!(
!texts.iter().any(|t| t.contains("to be undone")),
"{texts:?}"
);
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn codex_compacted_recovered_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".codex/sessions");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
if !text.contains("\"type\":\"compacted\"") {
continue;
}
let rep_msgs = text.matches("replacement_history").count();
if rep_msgs == 0 {
continue;
}
let s = Session::from_codex_str(&text).unwrap();
assert!(
!s.messages.is_empty(),
"{}: compacted session normalized to zero messages",
path.display()
);
proven = true;
eprintln!(
"proven on {}: compacted session → {} messages (replacement_history applied)",
path.display(),
s.messages.len()
);
break;
}
assert!(proven, "no Codex file with a compacted record found");
}
#[test]
fn codex_collab_agent_messages_recovered_but_normal_deduped() {
let normal = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"hi"}]}}
{"type":"event_msg","payload":{"type":"agent_message","phase":"final_answer","message":"the answer is 42"}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"the answer is 42"}]}}
"#;
let s = Session::from_codex_str(normal).unwrap();
let assistants = s
.messages
.iter()
.filter(|m| m.role == Role::Assistant)
.count();
assert_eq!(assistants, 1, "duplicate agent_message must be deduped");
let collab = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"do the task"}]}}
{"type":"event_msg","payload":{"type":"agent_message","phase":"commentary","message":"I'll inspect the repo first."}}
{"type":"event_msg","payload":{"type":"agent_message","phase":"commentary","message":"Now running the tests."}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"All done."}]}}
"#;
let s = Session::from_codex_str(collab).unwrap();
let texts: Vec<String> = s
.messages
.iter()
.filter(|m| m.role == Role::Assistant)
.filter_map(|m| m.content.clone())
.collect();
assert!(
texts.iter().any(|t| t.contains("inspect the repo")),
"{texts:?}"
);
assert!(
texts.iter().any(|t| t.contains("running the tests")),
"{texts:?}"
);
assert!(texts.iter().any(|t| t.contains("All done")), "{texts:?}");
assert_eq!(
texts.len(),
3,
"two recovered narration turns + one final answer"
);
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn codex_collab_narration_recovered_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".codex/sessions");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
let agent_msgs = text.matches("\"type\":\"agent_message\"").count();
let assistant_ri = text.matches("\"role\":\"assistant\"").count();
if agent_msgs < 50 || agent_msgs < assistant_ri * 3 + 10 {
continue;
}
let session = Session::from_codex_str(&text).unwrap();
let assistant_count = session
.messages
.iter()
.filter(|m| m.role == Role::Assistant)
.count();
assert!(
assistant_count > assistant_ri + 20,
"{}: only {assistant_count} assistant msgs recovered from {agent_msgs} agent_message events",
path.display()
);
proven = true;
eprintln!(
"proven on {}: {agent_msgs} agent_message events, {assistant_ri} response_item assistants → {assistant_count} assistant turns recovered",
path.display()
);
break;
}
assert!(proven, "no collab-pattern Codex file found to prove on");
}
#[test]
fn claude_attribution_and_system_content() {
let jsonl = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"done by skill"}]},"attributionSkill":"pm","slug":"my-slug","sessionId":"s"}
{"type":"system","subtype":"scheduled_task_fire","content":"Claude resuming /loop wakeup","sessionId":"s"}
{"type":"system","subtype":"local_command","content":"<command-name>/model</command-name>","sessionId":"s"}
{"type":"system","subtype":"turn_duration","durationMs":1234,"sessionId":"s"}
"#;
let s = Session::from_claude_code_str(jsonl).unwrap();
let a = s
.messages
.iter()
.find(|m| m.role == Role::Assistant)
.unwrap();
assert_eq!(
a.metadata.get("attributionSkill").map(String::as_str),
Some("pm")
);
assert_eq!(a.metadata.get("slug").map(String::as_str), Some("my-slug"));
let blob: String = s
.messages
.iter()
.filter(|m| m.role == Role::System)
.filter_map(|m| m.content.clone())
.collect::<Vec<_>>()
.join("\n");
assert!(blob.contains("resuming /loop wakeup"), "{blob}");
assert!(blob.contains("<command-name>/model"), "{blob}");
assert!(!blob.contains("1234"), "{blob}");
let wire = serde_json::to_string(&s.messages).unwrap();
assert!(!wire.contains("attributionSkill") && !wire.contains("systemSubtype"));
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn claude_system_content_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".claude/projects");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
let mut needle: Option<String> = None;
for line in text.lines() {
let Ok(v) = serde_json::from_str::<serde_json::Value>(line) else {
continue;
};
if v.get("type").and_then(|x| x.as_str()) != Some("system") {
continue;
}
let sub = v.get("subtype").and_then(|x| x.as_str()).unwrap_or("");
if matches!(
sub,
"scheduled_task_fire" | "local_command" | "away_summary"
) {
if let Some(c) = v.get("content").and_then(|x| x.as_str()) {
let snip: String = c
.trim_start()
.chars()
.take_while(|c| !c.is_control())
.take(30)
.collect();
if snip.trim().len() > 10 {
needle = Some(snip.trim().to_string());
break;
}
}
}
}
let Some(needle) = needle else { continue };
let s = Session::from_claude_code_str(&text).unwrap();
let blob: String = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect();
assert!(
blob.contains(&needle),
"{}: system content not folded",
path.display()
);
proven = true;
eprintln!(
"proven on {}: system subtype content folded",
path.display()
);
break;
}
assert!(
proven,
"no Claude session with a content-bearing system subtype found"
);
}
#[test]
fn reasoning_retained_in_metadata_not_on_wire() {
let codex = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"reasoning","encrypted_content":"OPAQUE","summary":[{"type":"summary_text","text":"weighed options A and B"}]}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"go with A"}]}}
"#;
let s = Session::from_codex_str(codex).unwrap();
let a = s
.messages
.iter()
.find(|m| m.role == Role::Assistant)
.unwrap();
assert!(a
.metadata
.get("reasoning")
.map(String::as_str)
.unwrap_or("")
.contains("options A and B"));
assert_eq!(
a.metadata.get("reasoning_encrypted").map(String::as_str),
Some("true")
);
let claude = r#"
{"type":"assistant","message":{"role":"assistant","content":[{"type":"thinking","thinking":"let me reason","signature":"sig-1"},{"type":"text","text":"answer"}]},"sessionId":"s"}
"#;
let s = Session::from_claude_code_str(claude).unwrap();
let a = s
.messages
.iter()
.find(|m| m.role == Role::Assistant)
.unwrap();
assert_eq!(
a.metadata.get("thinking").map(String::as_str),
Some("let me reason")
);
assert_eq!(
a.metadata.get("thinking_signature").map(String::as_str),
Some("sig-1")
);
assert_eq!(
a.content.as_deref(),
Some("answer"),
"thinking is not mixed into content"
);
let wire = serde_json::to_string(&s.messages).unwrap();
assert!(!wire.contains("thinking") && !wire.contains("reason"));
}
#[test]
fn codex_lineage_capture_and_tree_reconstruction() {
let parent = Session::from_codex_str(
r#"{"type":"session_meta","payload":{"id":"A","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"delegate"}]}}"#,
)
.unwrap();
let child = Session::from_codex_str(
r#"{"type":"session_meta","payload":{"id":"B","cwd":"/tmp","thread_source":"subagent","source":{"subagent":{"thread_spawn":{"parent_thread_id":"A","depth":1,"agent_nickname":"Gauss","agent_role":"worker"}}}}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"sub work"}]}}"#,
)
.unwrap();
assert_eq!(
child
.meta
.lineage
.get("parent_thread_id")
.map(String::as_str),
Some("A")
);
assert_eq!(
child.meta.lineage.get("agent_nickname").map(String::as_str),
Some("Gauss")
);
assert_eq!(
child.meta.lineage.get("thread_source").map(String::as_str),
Some("subagent")
);
let roots = Session::reconstruct_tree(vec![parent, child]);
assert_eq!(roots.len(), 1, "only the parent is a root");
assert_eq!(roots[0].meta.session_id.as_deref(), Some("A"));
assert_eq!(roots[0].subagents.len(), 1, "child attached under parent");
assert_eq!(roots[0].subagents[0].meta.session_id.as_deref(), Some("B"));
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn codex_subagent_lineage_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".codex/sessions");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
if !text.contains("\"thread_source\":\"subagent\"") {
continue;
}
let s = Session::from_codex_str(&text).unwrap();
if s.meta.lineage.contains_key("parent_thread_id") {
proven = true;
eprintln!(
"proven on {}: parent_thread_id={:?}",
path.display(),
s.meta.lineage.get("parent_thread_id")
);
break;
}
}
assert!(proven, "no Codex subagent rollout with lineage found");
}
#[test]
fn codex_thread_goal_and_review_recovered() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"event_msg","payload":{"type":"thread_goal_updated","goal":{"objective":"Stabilize the orchestrator"}}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"start review"}]}}
{"type":"event_msg","payload":{"type":"entered_review_mode"}}
{"type":"event_msg","payload":{"type":"exited_review_mode","review_output":{"findings":[],"overall_correctness":"patch is correct","overall_explanation":"All good; no issues found."}}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let blob: String = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect::<Vec<_>>()
.join("\n");
assert!(
blob.contains("[thread goal] Stabilize the orchestrator"),
"{blob}"
);
assert!(
blob.contains("[code review]") && blob.contains("no issues found"),
"{blob}"
);
}
#[test]
fn claude_user_provenance_and_tool_pairing_edge() {
let jsonl = r#"
{"type":"user","message":{"role":"user","content":"real prompt"},"promptSource":"typed","sessionId":"s"}
{"type":"user","message":{"role":"user","content":"injected"},"promptSource":"system","isMeta":true,"origin":{"kind":"task-notification"},"sessionId":"s"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"t1","name":"Read","input":{}}]},"sessionId":"s"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":"data"}]},"sourceToolAssistantUUID":"asst-uuid-9","sessionId":"s"}
"#;
let s = Session::from_claude_code_str(jsonl).unwrap();
let users: Vec<&supercode::ChatMessage> =
s.messages.iter().filter(|m| m.role == Role::User).collect();
assert_eq!(
users[0].metadata.get("promptSource").map(String::as_str),
Some("typed")
);
assert_eq!(
users[1].metadata.get("promptSource").map(String::as_str),
Some("system")
);
assert_eq!(
users[1].metadata.get("isMeta").map(String::as_str),
Some("true")
);
assert_eq!(
users[1].metadata.get("origin").map(String::as_str),
Some("task-notification")
);
let tool = s.messages.iter().find(|m| m.role == Role::Tool).unwrap();
assert_eq!(
tool.metadata
.get("sourceToolAssistantUUID")
.map(String::as_str),
Some("asst-uuid-9")
);
let wire = serde_json::to_string(&s.messages).unwrap();
assert!(!wire.contains("promptSource") && !wire.contains("sourceToolAssistantUUID"));
}
#[test]
fn claude_compaction_summary_is_marked() {
let jsonl = r#"
{"type":"user","message":{"role":"user","content":"real turn"},"promptSource":"typed","sessionId":"s"}
{"type":"system","subtype":"compact_boundary","content":"Conversation compacted","sessionId":"s"}
{"type":"user","message":{"role":"user","content":"<summary of earlier conversation>"},"isCompactSummary":true,"isVisibleInTranscriptOnly":true,"sessionId":"s"}
"#;
let s = Session::from_claude_code_str(jsonl).unwrap();
let summary = s
.messages
.iter()
.find(|m| m.metadata.get("isCompactSummary").map(String::as_str) == Some("true"))
.expect("compaction summary tagged");
assert!(summary
.content
.as_deref()
.unwrap_or("")
.contains("summary of earlier"));
assert_eq!(
summary
.metadata
.get("isVisibleInTranscriptOnly")
.map(String::as_str),
Some("true")
);
let real = s
.messages
.iter()
.find(|m| m.content.as_deref() == Some("real turn"))
.unwrap();
assert!(!real.metadata.contains_key("isCompactSummary"));
}
#[test]
fn codex_turn_id_preserved() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"hi"}],"metadata":{"turn_id":"turn-7"}}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let a = s
.messages
.iter()
.find(|m| m.role == Role::Assistant)
.unwrap();
assert_eq!(
a.metadata.get("turn_id").map(String::as_str),
Some("turn-7")
);
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn claude_promptsource_preserved_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".claude/projects");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
if !text.contains("\"promptSource\":\"typed\"") {
continue;
}
let s = Session::from_claude_code_str(&text).unwrap();
if s.messages
.iter()
.any(|m| m.metadata.get("promptSource").map(String::as_str) == Some("typed"))
{
proven = true;
eprintln!("proven on {}: promptSource preserved", path.display());
break;
}
}
assert!(proven, "no Claude session with promptSource=typed found");
}
#[test]
fn codex_assistant_phase_preserved() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"assistant","phase":"commentary","content":[{"type":"output_text","text":"thinking out loud"}]}}
{"type":"response_item","payload":{"type":"message","role":"assistant","phase":"final_answer","content":[{"type":"output_text","text":"the answer"}]}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let phases: Vec<Option<&String>> = s
.messages
.iter()
.filter(|m| m.role == Role::Assistant)
.map(|m| m.metadata.get("phase"))
.collect();
assert_eq!(phases.len(), 2);
assert_eq!(phases[0].map(String::as_str), Some("commentary"));
assert_eq!(phases[1].map(String::as_str), Some("final_answer"));
let wire = serde_json::to_string(&s.messages).unwrap();
assert!(!wire.contains("phase"), "metadata must be skip-serialized");
assert!(
!wire.contains("metadata"),
"metadata must be skip-serialized"
);
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn codex_phase_preserved_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".codex/sessions");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(40_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
if !text.contains("\"phase\":\"final_answer\"")
|| !text.contains("\"phase\":\"commentary\"")
{
continue;
}
let s = Session::from_codex_str(&text).unwrap();
let has_commentary = s
.messages
.iter()
.any(|m| m.metadata.get("phase").map(String::as_str) == Some("commentary"));
let has_final = s
.messages
.iter()
.any(|m| m.metadata.get("phase").map(String::as_str) == Some("final_answer"));
if has_commentary && has_final {
proven = true;
eprintln!("proven on {}: phase labels preserved", path.display());
break;
}
}
assert!(proven, "no Codex session with both phases found");
}
#[test]
fn unanswered_tool_calls_get_synthetic_results() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"go"}]}}
{"type":"response_item","payload":{"type":"function_call","call_id":"unanswered","name":"bash","arguments":"{}"}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let calls: Vec<String> = s
.messages
.iter()
.flat_map(|m| m.tool_calls().iter().map(|c| c.id.clone()))
.collect();
let results: Vec<String> = s
.messages
.iter()
.filter(|m| m.role == Role::Tool)
.filter_map(|m| m.tool_call_id.clone())
.collect();
assert!(
results.contains(&"unanswered".to_string()),
"synthetic result added"
);
assert_eq!(calls.len(), results.len(), "every call answered");
let call_idx = s
.messages
.iter()
.position(|m| !m.tool_calls().is_empty())
.unwrap();
assert_eq!(s.messages[call_idx + 1].role, Role::Tool);
assert_eq!(
s.messages[call_idx + 1].tool_call_id.as_deref(),
Some("unanswered")
);
}
#[test]
fn paired_sessions_are_left_unchanged() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"function_call","call_id":"c","name":"x","arguments":"{}"}}
{"type":"response_item","payload":{"type":"function_call_output","call_id":"c","output":"ok"}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
assert!(!s
.messages
.iter()
.any(|m| m.content.as_deref() == Some("[no tool result recorded — turn interrupted]")));
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn unanswered_tool_calls_paired_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let mut proven = false;
for sub in [".codex/sessions", ".claude/projects"] {
let root = PathBuf::from(&home).join(sub);
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(20_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
let s = Session::load(path).unwrap_or_else(|_| {
Session::from_codex_str(&text)
.unwrap_or_else(|_| Session::from_claude_code_str(&text).unwrap())
});
let calls: std::collections::HashSet<String> = s
.messages
.iter()
.flat_map(|m| m.tool_calls().iter().map(|c| c.id.clone()))
.filter(|id| !id.is_empty())
.collect();
if calls.is_empty() {
continue;
}
let results: std::collections::HashSet<String> = s
.messages
.iter()
.filter(|m| m.role == Role::Tool)
.filter_map(|m| m.tool_call_id.clone())
.collect();
assert!(
calls.is_subset(&results),
"{}: tool calls without results after pairing",
path.display()
);
if s.messages.iter().any(|m| {
m.content.as_deref() == Some("[no tool result recorded — turn interrupted]")
}) {
proven = true;
eprintln!("proven on {}: unanswered tool call paired", path.display());
}
if proven {
break;
}
}
if proven {
break;
}
}
assert!(
proven,
"no session with an unanswered tool call found to prove on"
);
}
#[test]
fn codex_server_tools_and_namespace() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s","cwd":"/tmp"}}
{"type":"response_item","payload":{"type":"tool_search_call","call_id":"ts1","arguments":{"query":"find tools"}}}
{"type":"response_item","payload":{"type":"tool_search_output","call_id":"ts1","tools":[{"type":"namespace","name":"multi_agent"}]}}
{"type":"response_item","payload":{"type":"web_search_call","status":"completed"}}
{"type":"response_item","payload":{"type":"image_generation_call","status":"completed","revised_prompt":"a blue circle"}}
{"type":"response_item","payload":{"type":"function_call","call_id":"f1","name":"create_issue","namespace":"linear","arguments":"{}"}}
{"type":"response_item","payload":{"type":"function_call_output","call_id":"f1","output":"ok"}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let ts_call = s.messages.iter().find_map(|m| {
m.tool_calls()
.iter()
.find(|c| c.function.name == "tool_search")
.cloned()
});
let ts_call = ts_call.expect("tool_search call present");
assert_eq!(ts_call.id, "ts1");
assert!(s.messages.iter().any(|m| m.role == Role::Tool
&& m.tool_call_id.as_deref() == Some("ts1")
&& m.content.as_deref().unwrap_or("").contains("multi_agent")));
let blob: String = s
.messages
.iter()
.filter_map(|m| m.content.clone())
.collect();
assert!(blob.contains("[web_search]"), "{blob}");
assert!(blob.contains("[image_generation] a blue circle"), "{blob}");
let fc = s
.messages
.iter()
.find_map(|m| m.tool_calls().iter().find(|c| c.id == "f1").cloned())
.expect("function call f1");
assert_eq!(fc.function.name, "linear__create_issue");
let calls: usize = s.messages.iter().map(|m| m.tool_calls().len()).sum();
let results = s.messages.iter().filter(|m| m.role == Role::Tool).count();
assert_eq!(calls, results, "every tool call has a matching result");
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn claude_subagents_attached_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let projects = PathBuf::from(&home).join(".claude/projects");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&projects)
.standard_filters(false)
.build();
for entry in walker.flatten() {
let path = entry.path();
if path.is_dir() && path.file_name().and_then(|n| n.to_str()) == Some("subagents") {
let Some(session_dir) = path.parent() else {
continue;
};
let Some(proj) = session_dir.parent() else {
continue;
};
let Some(stem) = session_dir.file_name().and_then(|n| n.to_str()) else {
continue;
};
let main = proj.join(format!("{stem}.jsonl"));
if !main.is_file() {
continue;
}
let has_agent_file = std::fs::read_dir(path)
.map(|rd| {
rd.flatten()
.any(|e| e.path().extension().and_then(|x| x.to_str()) == Some("jsonl"))
})
.unwrap_or(false);
if !has_agent_file {
continue;
}
let session = Session::load(&main).unwrap();
assert!(
!session.subagents.is_empty(),
"{}: has a subagents/ dir but no subagents attached",
main.display()
);
let sub_msgs: usize = session.subagents.iter().map(|s| s.messages.len()).sum();
assert!(
sub_msgs > 0,
"{}: subagents attached but carry no messages",
main.display()
);
assert!(
session.subagents.iter().all(|s| s.meta.agent_id.is_some()),
"{}: a subagent is missing its agent_id",
main.display()
);
proven = true;
let linked = session
.subagents
.iter()
.filter(|s| s.meta.parent_tool_use_id.is_some())
.count();
eprintln!(
"proven on {}: {} subagent(s), {sub_msgs} sub-messages, {linked} linked to a Task call",
main.display(),
session.subagents.len()
);
break;
}
}
assert!(
proven,
"no Claude Code session with both a main transcript and subagents/ found"
);
}
#[test]
fn codex_custom_tool_calls_are_normalized() {
let jsonl = r#"
{"type":"session_meta","payload":{"id":"s1","cwd":"/tmp"}}
{"type":"turn_context","payload":{"model":"gpt-5.5"}}
{"type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"patch the file"}]}}
{"type":"response_item","payload":{"type":"custom_tool_call","status":"completed","call_id":"call_abc","name":"apply_patch","input":"*** Begin Patch ***"}}
{"type":"response_item","payload":{"type":"custom_tool_call_output","call_id":"call_abc","output":"Success. Updated 1 file."}}
{"type":"response_item","payload":{"type":"message","role":"assistant","content":[{"type":"output_text","text":"done"}]}}
"#;
let s = Session::from_codex_str(jsonl).unwrap();
let roles: Vec<Role> = s.messages.iter().map(|m| m.role).collect();
assert_eq!(
roles,
vec![Role::User, Role::Assistant, Role::Tool, Role::Assistant]
);
let call = &s.messages[1].tool_calls()[0];
assert_eq!(call.id, "call_abc");
assert_eq!(call.function.name, "apply_patch");
assert!(call.function.arguments.contains("Begin Patch"));
assert_eq!(s.messages[2].tool_call_id.as_deref(), Some("call_abc"));
assert!(s.messages[2]
.content
.as_deref()
.unwrap_or("")
.contains("Success"));
}
#[test]
#[ignore = "requires local session corpus; set SUPERCODE_CORPUS=1"]
fn codex_custom_tool_calls_recovered_from_corpus() {
if std::env::var("SUPERCODE_CORPUS").is_err() {
panic!(
"SUPERCODE_CORPUS not set — this corpus test asserts nothing without \
the maintainer's local session logs; set SUPERCODE_CORPUS=1 to run it."
);
}
let home = std::env::var("HOME").unwrap();
let root = PathBuf::from(&home).join(".codex/sessions");
let mut proven = false;
let walker = ignore::WalkBuilder::new(&root)
.standard_filters(false)
.build();
for entry in walker.flatten().take(20_000) {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
continue;
}
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
if !text.contains("\"custom_tool_call\"") {
continue;
}
let Ok(session) = Session::from_codex_str(&text) else {
continue;
};
let raw_calls = text
.lines()
.filter(|l| l.contains("\"type\":\"custom_tool_call\""))
.count();
if raw_calls == 0 {
continue;
}
let normalized_calls: usize = session.messages.iter().map(|m| m.tool_calls().len()).sum();
assert!(
normalized_calls > 0,
"{}: {raw_calls} custom_tool_calls but 0 normalized",
path.display()
);
proven = true;
eprintln!(
"proven on {}: {raw_calls} raw custom_tool_calls → {normalized_calls} total tool calls",
path.display()
);
break;
}
assert!(
proven,
"no Codex file with custom_tool_call found to prove on"
);
}