use std::sync::atomic::{AtomicUsize, Ordering};
use io_harness::provider::{CompletionRequest, CompletionResponse, Record, Replay, ToolCall};
use io_harness::{
run_with, ApproveAll, Policy, Provider, RunOutcome, Store, TaskContract, Verification,
};
use serde_json::json;
struct Script {
at: AtomicUsize,
}
impl Provider for Script {
fn name(&self) -> &str {
"script"
}
async fn complete(&self, _req: CompletionRequest) -> io_harness::Result<CompletionResponse> {
let i = self.at.fetch_add(1, Ordering::SeqCst);
Ok(CompletionResponse {
text: Some(format!("turn {i}")),
tool_calls: vec![ToolCall {
name: "write_file".into(),
arguments: json!({
"path": format!("src/f{i}.rs"),
"content": format!("fn hello{i}() -> u32 {{ {i} }}\n"),
}),
}],
..Default::default()
})
}
}
fn workspace() -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
std::fs::create_dir_all(dir.path().join("src")).unwrap();
dir
}
fn contract(root: &std::path::Path) -> TaskContract {
TaskContract::workspace(
"write a few files",
root,
Verification::WorkspaceFileContains {
file: "src/f2.rs".into(),
needle: "fn hello2".into(),
},
)
.with_max_steps(4)
}
fn open_policy() -> Policy {
Policy::default()
.layer("test")
.allow_read("*")
.allow_write("*")
.allow_exec("*")
}
#[tokio::test]
async fn one_case_replayed_twice_produces_the_same_trace() {
let cassette = tempfile::tempdir().unwrap();
let path = cassette.path().join("run.json");
{
let dir = workspace();
let store = Store::memory().unwrap();
let provider = Record::new(Script {
at: AtomicUsize::new(0),
});
let result = run_with(
&contract(dir.path()),
&provider,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
assert!(
matches!(result.outcome, RunOutcome::Success { .. }),
"the recorded run must actually do something: {result:?}"
);
provider.save(&path).unwrap();
}
let mut traces = Vec::new();
for _ in 0..2 {
let dir = workspace();
let store = Store::memory().unwrap();
let provider = Replay::load(&path).unwrap();
let result = run_with(
&contract(dir.path()),
&provider,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
assert!(
matches!(result.outcome, RunOutcome::Success { .. }),
"a replayed run must reach the same outcome: {result:?}"
);
traces.push(store.canonical_trace(result.run_id).unwrap());
}
assert_eq!(
traces[0], traces[1],
"two replays of one recording must produce the same canonical trace"
);
assert!(
!traces[0].is_empty(),
"an empty trace would make the comparison vacuous"
);
assert!(
traces[0].contains("fn hello0"),
"the trace must contain the run's real content, not just its shape:\n{}",
traces[0]
);
}
#[tokio::test]
async fn a_replay_matches_the_run_it_was_recorded_from() {
let cassette = tempfile::tempdir().unwrap();
let path = cassette.path().join("run.json");
let recorded = {
let dir = workspace();
let store = Store::memory().unwrap();
let provider = Record::new(Script {
at: AtomicUsize::new(0),
});
let result = run_with(
&contract(dir.path()),
&provider,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
provider.save(&path).unwrap();
store.canonical_trace(result.run_id).unwrap()
};
let replayed = {
let dir = workspace();
let store = Store::memory().unwrap();
let provider = Replay::load(&path).unwrap();
let result = run_with(
&contract(dir.path()),
&provider,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
store.canonical_trace(result.run_id).unwrap()
};
assert_eq!(
recorded, replayed,
"a replay must reproduce the run it came from, not just agree with itself"
);
}
#[test]
fn the_comparison_fails_when_a_run_id_reappears_in_the_prompt() {
let a = trace_with_prompt("- build: cargo test (step 1)");
let b = trace_with_prompt("- build: cargo test (run 2, step 1)");
assert_ne!(
a, b,
"a run id in the rendered prompt MUST break the comparison; if this \
passes, the determinism tests are decoration"
);
}
#[test]
fn the_comparison_fails_when_children_are_composed_in_a_different_order() {
let spawn_order =
trace_with_result("[child 2 \"ordered-0\" -> Success]\n[child 3 \"ordered-1\" -> Success]");
let completion_order =
trace_with_result("[child 3 \"ordered-1\" -> Success]\n[child 2 \"ordered-0\" -> Success]");
assert_ne!(
spawn_order, completion_order,
"reordered child results MUST break the comparison — same content, \
different order, which is precisely what buffer_unordered produced"
);
}
#[test]
fn two_identically_built_traces_compare_equal() {
assert_eq!(
trace_with_prompt("- build: cargo test (step 1)"),
trace_with_prompt("- build: cargo test (step 1)")
);
assert_eq!(
trace_with_result("[child 2 \"a\" -> Success]"),
trace_with_result("[child 2 \"a\" -> Success]")
);
}
fn trace_with_prompt(prompt: &str) -> String {
let store = Store::memory().unwrap();
let run = store.start_run("goal", "f.rs").unwrap();
store
.record(
run,
&io_harness::StepRecord::new(1, "read", "ok").with_trace(prompt, "read_file:{}", 10),
)
.unwrap();
store.canonical_trace(run).unwrap()
}
fn trace_with_result(result: &str) -> String {
let store = Store::memory().unwrap();
let run = store.start_run("goal", "f.rs").unwrap();
store
.record(
run,
&io_harness::StepRecord::new(1, "spawned", result).with_trace(
"p",
"spawn_agent:{}",
10,
),
)
.unwrap();
store.canonical_trace(run).unwrap()
}
#[tokio::test]
async fn a_workspace_replay_survives_being_interrupted_and_resumed() {
let cassette = tempfile::tempdir().unwrap();
let path = cassette.path().join("run.json");
{
let dir = workspace();
let store = Store::memory().unwrap();
let provider = Record::new(Script {
at: AtomicUsize::new(0),
});
run_with(
&contract(dir.path()),
&provider,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
provider.save(&path).unwrap();
}
let straight = {
let dir = workspace();
let store = Store::memory().unwrap();
let p = Replay::load(&path).unwrap();
let r = run_with(
&contract(dir.path()),
&p,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
store.canonical_trace(r.run_id).unwrap()
};
let interrupted = {
let dir = workspace();
let store = Store::memory().unwrap();
let p = Replay::load(&path).unwrap();
let cut_short = contract(dir.path()).with_max_steps(1);
let first = run_with(&cut_short, &p, &store, &open_policy(), &ApproveAll)
.await
.unwrap();
assert!(
matches!(first.outcome, RunOutcome::StepCapReached { .. }),
"the cap must stop it mid-task, not finish it: {first:?}"
);
let p2 = Replay::load(&path).unwrap();
let done = io_harness::resume_with(
&contract(dir.path()),
&p2,
&store,
first.run_id,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
store.canonical_trace(done.run_id).unwrap()
};
assert_eq!(
straight, interrupted,
"a workspace replay must survive an interruption, not merely report that it could not"
);
}
#[tokio::test]
async fn a_replay_still_refuses_a_request_that_was_never_recorded() {
let cassette = tempfile::tempdir().unwrap();
let path = cassette.path().join("run.json");
{
let dir = workspace();
let store = Store::memory().unwrap();
let provider = Record::new(Script {
at: AtomicUsize::new(0),
});
run_with(
&contract(dir.path()),
&provider,
&store,
&open_policy(),
&ApproveAll,
)
.await
.unwrap();
provider.save(&path).unwrap();
}
let dir = workspace();
let store = Store::memory().unwrap();
let p = Replay::load(&path).unwrap();
let other = TaskContract::workspace(
"a goal the recording never saw",
dir.path(),
Verification::WorkspaceFileContains {
file: "unreachable.txt".into(),
needle: "never".into(),
},
);
let err = run_with(&other, &p, &store, &open_policy(), &ApproveAll)
.await
.expect_err("an unrecorded request must refuse, not improvise");
assert!(
err.to_string().contains("diverged"),
"the error must name the divergence so it is debuggable, got: {err}"
);
}
#[tokio::test]
async fn a_single_file_replay_does_survive_being_interrupted_and_resumed() {
let cassette = tempfile::tempdir().unwrap();
let path = cassette.path().join("single.json");
struct Grower {
at: AtomicUsize,
}
impl Provider for Grower {
fn name(&self) -> &str {
"grower"
}
async fn complete(
&self,
_req: CompletionRequest,
) -> io_harness::Result<CompletionResponse> {
let i = self.at.fetch_add(1, Ordering::SeqCst);
let mut body = String::new();
for n in 0..=i {
body.push_str(&format!("fn hello{n}() -> u32 {{ {n} }}\n"));
}
Ok(CompletionResponse {
tool_calls: vec![ToolCall {
name: "write_file".into(),
arguments: json!({ "content": body }),
}],
..Default::default()
})
}
}
let single = |dir: &std::path::Path| {
TaskContract::new(
"grow the file",
dir.join("a.rs"),
Verification::FileContains("fn hello2".into()),
)
.with_max_steps(4)
};
{
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("a.rs"), "").unwrap();
let store = Store::memory().unwrap();
let provider = Record::new(Grower {
at: AtomicUsize::new(0),
});
let r = io_harness::run(&single(dir.path()), &provider, &store)
.await
.unwrap();
assert!(
matches!(r.outcome, RunOutcome::Success { .. }),
"the recorded run must succeed: {r:?}"
);
provider.save(&path).unwrap();
}
let straight = {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("a.rs"), "").unwrap();
let store = Store::memory().unwrap();
let p = Replay::load(&path).unwrap();
let r = io_harness::run(&single(dir.path()), &p, &store)
.await
.unwrap();
store.canonical_trace(r.run_id).unwrap()
};
let interrupted = {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("a.rs"), "").unwrap();
let store = Store::memory().unwrap();
let p = Replay::load(&path).unwrap();
let cut = single(dir.path()).with_max_steps(1);
let first = io_harness::run(&cut, &p, &store).await.unwrap();
assert!(
matches!(first.outcome, RunOutcome::StepCapReached { .. }),
"the cap must cut it short: {first:?}"
);
let p2 = Replay::load(&path).unwrap();
let done = io_harness::resume(&single(dir.path()), &p2, &store, first.run_id)
.await
.unwrap();
assert!(
matches!(done.outcome, RunOutcome::Success { .. }),
"the resumed replay must finish: {done:?}"
);
store.canonical_trace(done.run_id).unwrap()
};
assert_eq!(
straight, interrupted,
"a single-file replay must survive an interruption"
);
}