use amberfork_model::{AttributionMode, DiffResult};
use assert_cmd::Command;
use std::net::TcpStream;
use std::path::{Path, PathBuf};
use std::time::Duration;
const OLLAMA_URL: &str = "http://127.0.0.1:11434";
const OLLAMA_ADDR: &str = "127.0.0.1:11434";
const BASE_URL_ENV: &str = "AMBERFORK_VERIFY_BASE_URL";
const MAX_FORK_ATTEMPTS: u32 = 6;
fn agent_script() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/verify_agent.py")
}
fn amberfork() -> Command {
Command::cargo_bin("amberfork").expect("amberfork binary builds")
}
fn ollama_reachable() -> bool {
TcpStream::connect_timeout(&OLLAMA_ADDR.parse().unwrap(), Duration::from_millis(500)).is_ok()
}
fn amberfork_record(out: &Path, id: &str) -> Command {
let mut cmd = amberfork();
cmd.arg("record")
.arg("--upstream")
.arg(OLLAMA_URL)
.arg("--base-url-env")
.arg(BASE_URL_ENV)
.arg("--out")
.arg(out)
.arg("--id")
.arg(id)
.arg("--")
.arg("python3")
.arg(agent_script());
cmd
}
fn diff_result(stdout: &[u8]) -> DiffResult {
serde_json::from_slice(stdout).expect("--json stdout is a valid DiffResult")
}
#[test]
#[ignore = "network: drives a real subprocess against a local Ollama server, see this file's doc comment for the recipe"]
fn verify_reports_an_honest_recovery_verdict_against_a_real_local_provider() {
assert!(
ollama_reachable(),
"Ollama is not reachable at {OLLAMA_URL} — start it with `ollama serve` and \
`ollama pull smollm2:135m` first (see this file's doc comment)"
);
let dir = tempfile::tempdir().expect("tempdir");
let good = dir.path().join("good.cassette.json");
let bad = dir.path().join("bad.cassette.json");
amberfork_record(&good, "good").assert().code(0);
let mut forked = false;
for attempt in 1..=MAX_FORK_ATTEMPTS {
amberfork_record(&bad, "bad").assert().code(0);
let probe = amberfork()
.arg("diff")
.arg(&bad)
.arg("--against")
.arg(&good)
.arg("--json")
.output()
.expect("diff runs");
if diff_result(&probe.stdout).fork.is_some() {
forked = true;
break;
}
eprintln!("attempt {attempt}/{MAX_FORK_ATTEMPTS}: good/bad recordings converged, retrying");
}
assert!(
forked,
"the real model answered identically across {MAX_FORK_ATTEMPTS} independent recordings — \
rerun the test; temperature-driven sampling should diverge within a few tries"
);
let assert = amberfork()
.arg("diff")
.arg(&bad)
.arg("--against")
.arg(&good)
.arg("--verify")
.arg("--json")
.arg("--upstream")
.arg(OLLAMA_URL)
.arg("--base-url-env")
.arg(BASE_URL_ENV)
.arg("--runs")
.arg("3")
.arg("--")
.arg("python3")
.arg(agent_script())
.assert()
.code(1);
let result = diff_result(&assert.get_output().stdout);
let attribution = result
.attribution
.expect("a two-sided fork with --verify always upgrades to an attribution");
assert_eq!(attribution.mode, AttributionMode::Counterfactual);
let counterfactual = attribution
.counterfactual
.expect("counterfactual mode always carries counterfactual evidence");
assert_eq!(counterfactual.runs, 3);
eprintln!("counterfactual verdict: {:?}", counterfactual.recovered);
}