//! Budget-abort test (parent spec §Error handling / Budget-level).
//! Mock run with deliberately tiny budget; asserts the harness
//! stops with RUN_STATUS=budget_exceeded and that the affected rows
//! carry final_status=budget_abort.

use std::path::PathBuf;
use std::process::Command;

fn harness_bin() -> PathBuf { PathBuf::from(env!("CARGO_BIN_EXE_xmodel-harness")) }

fn experiment_root() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR")).parent().unwrap().to_path_buf()
}

#[test]
fn tiny_budget_aborts_run_cleanly() {
    let out = tempfile::Builder::new().prefix("cma2-budget-").tempdir().unwrap();
    let status = Command::new(harness_bin())
        .arg("--rendered").arg(experiment_root().join("rendered"))
        .arg("--tasks").arg(experiment_root().join("master").join("tasks"))
        .arg("--out").arg(out.path())
        .arg("--model").arg("mock")
        .arg("--mock").arg(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests").join("fixtures").join("mock_full_run.json"))
        .arg("--token-budget").arg("1500")  // less than one task's worth (~1200 per turn)
        .status()
        .expect("running xmodel-harness");
    assert!(status.success(), "harness should exit 0 on budget exhaustion");

    let mut entries = std::fs::read_dir(out.path()).unwrap();
    let run_dir = entries.next().unwrap().unwrap().path();
    let status_str = std::fs::read_to_string(run_dir.join("RUN_STATUS")).unwrap();
    assert_eq!(status_str, "budget_exceeded");
    let scores = std::fs::read_to_string(run_dir.join("scores.csv")).unwrap();
    // At least one row must carry budget_abort.
    assert!(
        scores.lines().any(|l| l.ends_with(",budget_abort")),
        "expected at least one budget_abort row; got:\n{}", scores,
    );
}
