use serde_json::Value;
use abstractcode::runner::rehydrate_run_into;
use abstractcode::transcript::{Fold, Item, ToolStatus};
fn fold_fixture() -> Fold {
let raw = include_str!("fixtures/history_bundle_restore.json");
let bundle: Value = serde_json::from_str(raw).expect("fixture parses");
let root = bundle["root_run_id"].as_str().expect("root id").to_string();
let mut fold = Fold::new();
let mut fx = Vec::new();
let contributed = rehydrate_run_into(&mut fold, &root, &bundle, true, &mut fx);
assert!(contributed, "the bundle must contribute transcript items");
fold
}
#[test]
fn restored_tool_cards_reach_final_states() {
let fold = fold_fixture();
let tools: Vec<(&String, &ToolStatus)> = fold
.items
.iter()
.filter_map(|i| match i {
Item::Tool { name, status, .. } => Some((name, status)),
_ => None,
})
.collect();
assert!(
tools.len() >= 3,
"the fixture carries two tool batches (3 calls): {tools:?}"
);
for (name, status) in &tools {
assert!(
matches!(status, ToolStatus::Ok | ToolStatus::Failed),
"restored card '{name}' stuck in non-final state {status:?}"
);
}
}
#[test]
fn slimmed_completion_still_finishes_the_card() {
let fold = fold_fixture();
let write_file = fold
.items
.iter()
.find_map(|i| match i {
Item::Tool {
name,
status,
result,
..
} if name == "write_file" => Some((status, result)),
_ => None,
})
.expect("write_file card present");
assert_eq!(*write_file.0, ToolStatus::Ok);
assert!(
write_file.1.contains("Successfully written"),
"result preview from the slimmed record's results: {}",
write_file.1
);
}
#[test]
fn per_result_success_flags_are_honored() {
let fold = fold_fixture();
let status_of = |wanted: &str| {
fold.items.iter().find_map(|i| match i {
Item::Tool { name, status, .. } if name == wanted => Some(*status),
_ => None,
})
};
assert_eq!(status_of("list_files"), Some(ToolStatus::Failed));
assert_eq!(status_of("execute_command"), Some(ToolStatus::Ok));
}
#[test]
fn restore_counts_slimmed_tool_calls_and_holds_no_wait() {
let fold = fold_fixture();
assert!(
fold.pending_wait.is_none(),
"a prior run's answered waits must never prompt after restore"
);
assert_eq!(fold.stats.tool_calls, 3);
assert!(fold.stats.llm_calls >= 2);
}
#[test]
fn server_bundle_warnings_render_ahead_and_survive_ledgerless_bundles() {
let bundle = serde_json::json!({
"root_run_id": "root",
"warnings": [
{"kind": "ledger_tail_window", "detail": "run root: 2500 total, window carried 2000"},
"torn_rows_skipped: 3",
],
"ledgers": {
"root": {"run_id": "root", "total": 1, "items": [
{"cursor": 1, "record": {"run_id": "root", "node_id": "end",
"status": "completed", "result": {"output": {"response": "done"}}}}
]}
}
});
let mut fold = Fold::new();
fold.begin_run("root");
let mut fx = Vec::new();
rehydrate_run_into(&mut fold, "root", &bundle, false, &mut fx);
let infos: Vec<&String> = fold
.items
.iter()
.filter_map(|i| match i {
Item::Info { text } => Some(text),
_ => None,
})
.collect();
assert!(
infos
.iter()
.any(|t| t.contains("ledger_tail_window") && t.contains("2000")),
"object warning renders kind + detail: {infos:?}"
);
assert!(
infos.iter().any(|t| t.contains("torn_rows_skipped")),
"bare-string warning renders: {infos:?}"
);
let first_warning = fold
.items
.iter()
.position(|i| matches!(i, Item::Info { text } if text.contains("history export")))
.expect("warning rendered");
let answer = fold
.items
.iter()
.position(|i| matches!(i, Item::Assistant { .. }))
.expect("answer folded");
assert!(first_warning < answer, "warnings render AHEAD of the fold");
let bare = serde_json::json!({
"root_run_id": "root",
"warnings": [{"kind": "subtree_discovery_failed", "detail": "walk aborted"}]
});
let mut fold2 = Fold::new();
fold2.begin_run("root");
let mut fx2 = Vec::new();
rehydrate_run_into(&mut fold2, "root", &bare, false, &mut fx2);
assert!(
fold2
.items
.iter()
.any(|i| matches!(i, Item::Info { text } if text.contains("subtree_discovery_failed"))),
"ledger-less bundles surface warnings too"
);
let many: Vec<Value> = (0..9)
.map(|i| Value::String(format!("warning {i}")))
.collect();
let capped = serde_json::json!({
"root_run_id": "root",
"warnings": many,
"ledgers": {}
});
let mut fold3 = Fold::new();
fold3.begin_run("root");
let mut fx3 = Vec::new();
rehydrate_run_into(&mut fold3, "root", &capped, false, &mut fx3);
let shown = fold3
.items
.iter()
.filter(|i| matches!(i, Item::Info { text } if text.contains("history export")))
.count();
assert_eq!(shown, 7, "6 warnings + the +3-more line");
assert!(fold3
.items
.iter()
.any(|i| matches!(i, Item::Info { text } if text.contains("+3 more"))));
}