use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, Request, Respond, ResponseTemplate};
mod common;
#[path = "headless_cli/smart_startup.rs"]
mod smart_startup;
const NEMOTRON_MODEL: &str = "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16";
#[tokio::test(flavor = "multi_thread")]
async fn smart_solve_admits_private_storage_before_loading_the_auxiliary() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: Arc::new(Mutex::new(Vec::new())),
})
.mount(&server)
.await;
for (exposed, extra_grant, unsafe_exec) in [
(true, false, false),
(false, true, false),
(false, false, true),
(false, false, false),
] {
let mut command = common::newt();
let home = command.home().to_path_buf();
let workspace = home.join("workspace");
std::fs::create_dir(&workspace).unwrap();
let frame = if exposed {
workspace.join("frame")
} else {
home.join("private-frame")
};
let config = home.join("config.toml");
std::fs::write(
&config,
format!(
r#"default_backend = "fixture"
[[backends]]
name = "fixture"
endpoint = "{}"
model = "fixture"
kind = "openai"
[smart_harness]
device = "cuda"
"#,
server.uri()
),
)
.unwrap();
let instruction = workspace.join("task.md");
std::fs::write(&instruction, "Read the workspace.").unwrap();
command
.arg("--config")
.arg(&config)
.args(["headless", "--smart-harness", "--cwd"])
.arg(&workspace)
.arg("--instruction-file")
.arg(&instruction)
.arg("--frame-dir")
.arg(&frame);
if extra_grant {
command.env("NEWT_READ_PATHS", &home);
}
if unsafe_exec {
command.arg("--unsafe-host-exec");
}
let expected = if unsafe_exec {
"requires confined launch authority"
} else if !cfg!(any(target_os = "linux", target_os = "macos"))
|| !newt_core::ocap_l3_backend().1
{
"requires object-bound filesystem tools and a supported kernel sandbox"
} else if exposed || extra_grant {
"frame storage overlaps model filesystem authority"
} else {
"requires an external backend"
};
let refused = unsafe_exec
|| exposed
|| extra_grant
|| !cfg!(any(target_os = "linux", target_os = "macos"))
|| !newt_core::ocap_l3_backend().1;
let assertion = command.assert().stderr(predicates::str::contains(expected));
if refused {
assertion.success().stderr(predicates::str::contains(
"smart harness disabled for this session",
));
} else {
assertion.failure(); }
assert!(!frame.exists(), "rejected launch must not create a frame");
}
}
fn has_one_round_action_nudge(body: &serde_json::Value) -> bool {
body["messages"].as_array().is_some_and(|messages| {
messages.iter().any(|message| {
message["role"] == "user"
&& message["content"]
.as_str()
.is_some_and(|content| content.starts_with("[1 read-only rounds so far."))
})
})
}
struct ReadThenFinishOnNudge {
requests: Arc<Mutex<Vec<serde_json::Value>>>,
sequence: AtomicUsize,
}
struct CaptureThenFinish {
requests: Arc<Mutex<Vec<serde_json::Value>>>,
}
impl Respond for CaptureThenFinish {
fn respond(&self, request: &Request) -> ResponseTemplate {
let body: serde_json::Value =
serde_json::from_slice(&request.body).expect("chat request is JSON");
let streaming = body["stream"].as_bool().unwrap_or(false);
self.requests
.lock()
.expect("request capture lock")
.push(body);
if streaming {
let frame = serde_json::json!({"choices": [{"delta": {"content": "done"}, "finish_reason": "stop"}]});
let usage = serde_json::json!({"choices": [], "usage": {"prompt_tokens": 10, "completion_tokens": 7}});
let sse = format!("data: {frame}\n\ndata: {usage}\n\ndata: [DONE]\n\n");
return ResponseTemplate::new(200).set_body_raw(sse.into_bytes(), "text/event-stream");
}
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": NEMOTRON_MODEL,
"choices": [{
"message": {"role": "assistant", "content": "done"},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 10, "completion_tokens": 7}
}))
}
}
fn contract_from(path: &std::path::Path) -> serde_json::Value {
let records: Vec<serde_json::Value> = std::fs::read_to_string(path)
.expect("read headless events")
.lines()
.map(|line| serde_json::from_str(line).expect("event line is JSON"))
.collect();
let mut contracts = records
.into_iter()
.filter(|record| record.get("contract_version").is_some());
let contract = contracts.next().expect("one headless contract");
assert!(contracts.next().is_none(), "exactly one headless contract");
contract
}
fn advertised_tool(body: &serde_json::Value, name: &str) -> bool {
body["tools"].as_array().is_some_and(|tools| {
tools
.iter()
.any(|tool| tool["function"]["name"].as_str() == Some(name))
})
}
impl Respond for ReadThenFinishOnNudge {
fn respond(&self, request: &Request) -> ResponseTemplate {
let body: serde_json::Value =
serde_json::from_slice(&request.body).expect("chat request is JSON");
self.requests
.lock()
.expect("request capture lock")
.push(body.clone());
if has_one_round_action_nudge(&body) || body.get("tools").is_none() {
return ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": NEMOTRON_MODEL,
"choices": [{
"message": {"role": "assistant", "content": "nudge received; done"},
"finish_reason": "stop"
}]
}));
}
let sequence = self.sequence.fetch_add(1, Ordering::SeqCst);
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": NEMOTRON_MODEL,
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": format!("read_{sequence}"),
"type": "function",
"function": {"name": "list_dir", "arguments": "{\"path\":\".\"}"}
}]
},
"finish_reason": "tool_calls"
}]
}))
}
}
#[tokio::test(flavor = "multi_thread")]
async fn a_pre_split_config_applies_nemotron_initiative_to_runtime_and_contract() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ReadThenFinishOnNudge {
requests: requests.clone(),
sequence: AtomicUsize::new(0),
})
.mount(&server)
.await;
let workspace = tempfile::tempdir().expect("temporary headless workspace");
let config_path = workspace.path().join("benchmark.toml");
let instruction_path = workspace.path().join("instruction.md");
let events_path = workspace.path().join("events.jsonl");
let models_dir = workspace.path().join("models");
std::fs::create_dir_all(&models_dir).expect("models dir");
std::fs::write(
models_dir.join("nemo-run.toml"),
format!(
"name = \"nemo-run\"\nbackend = \"vllm\"\nfamily = \"nemotron\"\n\n[vllm]\nserved_name = \"{NEMOTRON_MODEL}\"\n"
),
)
.expect("write family card");
std::fs::write(
&config_path,
format!(
r#"default_backend = "nemotron"
[[backends]]
name = "nemotron"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
card = "nemo-run"
[tenacity]
default = "relaxed"
[tenacity.families]
nemotron = "relentless"
"#,
server.uri()
),
)
.expect("write explicit headless config");
let config_before = std::fs::read_to_string(&config_path).expect("read config back");
std::fs::write(
&instruction_path,
"Inspect the workspace, then complete the task.\n",
)
.expect("write headless instruction");
std::fs::write(workspace.path().join("tool-ground-truth.txt"), "present\n")
.expect("write list_dir ground-truth marker");
common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "2"])
.assert()
.success()
.stderr(predicates::str::contains("uses old psyche labels"));
assert_eq!(
std::fs::read_to_string(&config_path).expect("read config back"),
config_before,
"an explicit config is migrated in memory, never rewritten"
);
let requests = requests.lock().expect("request capture lock");
assert!(requests.len() >= 2, "expected at least two chat requests");
let second_messages = requests[1]["messages"]
.as_array()
.expect("second request messages");
let second_user_messages: Vec<&str> = second_messages
.iter()
.filter(|message| message["role"] == "user")
.filter_map(|message| message["content"].as_str())
.collect();
assert!(
has_one_round_action_nudge(&requests[1]),
"eager must inject its action nudge after the first read-only round: \
{second_user_messages:?}"
);
let tool_results: Vec<&str> = second_messages
.iter()
.filter(|message| message["role"] == "tool")
.filter_map(|message| message["content"].as_str())
.collect();
assert!(
tool_results
.iter()
.any(|result| result.contains("tool-ground-truth.txt")),
"the real list_dir round must succeed against the temporary workspace: {tool_results:?}"
);
drop(requests);
let records: Vec<serde_json::Value> = std::fs::read_to_string(&events_path)
.expect("read headless events")
.lines()
.map(|line| serde_json::from_str(line).expect("event line is JSON"))
.collect();
let contracts: Vec<&serde_json::Value> = records
.iter()
.filter(|record| record.get("contract_version").is_some())
.collect();
assert_eq!(
contracts.len(),
1,
"headless emits exactly one contract record"
);
assert_eq!(contracts[0]["contract_version"], "2");
assert_eq!(contracts[0]["effective_config"]["initiative"], "eager");
assert_eq!(
contracts[0]["effective_config"]["tenacity"], "normal",
"a family sets initiative, never tenacity"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn a_cardless_nemotron_looking_alias_gets_no_family_initiative() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ReadThenFinishOnNudge {
requests: requests.clone(),
sequence: AtomicUsize::new(0),
})
.mount(&server)
.await;
let workspace = tempfile::tempdir().expect("temporary headless workspace");
let config_path = workspace.path().join("benchmark.toml");
let instruction_path = workspace.path().join("instruction.md");
let events_path = workspace.path().join("events.jsonl");
std::fs::write(
&config_path,
format!(
r#"default_backend = "nemotron"
[[backends]]
name = "nemotron"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
[initiative]
default = "patient"
[initiative.families]
nemotron = "eager"
"#,
server.uri()
),
)
.expect("write explicit headless config");
std::fs::write(&instruction_path, "Complete the task.\n").expect("write instruction");
common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "2"])
.assert()
.success();
let records: Vec<serde_json::Value> = std::fs::read_to_string(&events_path)
.expect("read headless events")
.lines()
.map(|line| serde_json::from_str(line).expect("event line is JSON"))
.collect();
let contract = records
.iter()
.find(|record| record.get("contract_version").is_some())
.expect("headless emits a contract record");
assert_eq!(
contract["effective_config"]["initiative"], "patient",
"a model-name alias is a LABEL — with no exact card family, the \
per-family default must not engage"
);
assert_eq!(contract["effective_config"]["tenacity"], "normal");
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_crew_and_obsessive_postures_reach_wire_and_contract() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let config_path = fixture.path().join("benchmark.toml");
let instruction_path = fixture.path().join("instruction.md");
std::fs::write(
&config_path,
format!(
r#"default_backend = "nemotron"
[[backends]]
name = "nemotron"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
api = "chat_completions"
[backends.capability]
reasoning_replay_scope = "current_user_turn"
[backends.capability.chat_completions]
cognition = true
chat_template_kwargs = true
parallel_tool_calls = false
bounded_reasoning_continuation = true
"#,
server.uri()
),
)
.expect("write explicit headless config");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
let cases = [
("bare", false, "default", "normal"),
("crew", true, "default", "normal"),
("obsessive", true, "meticulous", "relentless"),
];
for (name, crew, cognition, tenacity) in cases {
let obsessive = name == "obsessive";
let workspace = fixture.path().join(format!("ws-{name}"));
std::fs::create_dir(&workspace).expect("create headless workspace");
let events_path = fixture.path().join(format!("events-{name}.jsonl"));
let mut command = common::newt();
command.env_remove("NEWT_TEAM");
if obsessive {
command.arg("--obsessive");
} else if crew {
command.env("NEWT_TEAM", "1");
}
command
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(&workspace)
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
let body = requests
.lock()
.expect("request capture lock")
.pop()
.expect("one captured request");
assert_eq!(advertised_tool(&body, "crew"), crew, "{name}: {body}");
assert_eq!(
advertised_tool(&body, "compose_roster"),
crew,
"{name}: {body}"
);
if obsessive {
assert_eq!(body["max_tokens"], 16000);
assert_eq!(body["chat_template_kwargs"]["enable_thinking"], true);
} else {
assert!(
body.get("chat_template_kwargs").is_none(),
"default cognition means Newt sends no thinking selection: {body}"
);
}
let contract = contract_from(&events_path);
assert_eq!(contract["effective_config"]["cognition"], cognition);
assert_eq!(
contract["effective_config"]["crew"],
if crew { "on" } else { "off" }
);
assert_eq!(contract["effective_config"]["tenacity"], tenacity);
assert_eq!(
contract["effective_config"]["initiative"], "measured",
"{name}: obsessive leaves initiative alone"
);
let features = &contract["receipt"]["features"];
let crew_state = if crew { "instantiated" } else { "unavailable" };
assert_eq!(features["crew"]["state"], crew_state, "{name}: {contract}");
assert!(!advertised_tool(&body, "code_search"));
assert!(!advertised_tool(&body, "state_set"));
assert!(!body.to_string().contains("</state>"));
assert_eq!(features["code_search"]["state"], "unsupported");
assert_eq!(features["scratchpad"]["state"], "unavailable");
}
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_refuses_an_invalid_output_allowance_before_inference() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
for (extra, expected) in [
(vec!["--output-allowance", "0"], "output_allowance 0 permits no output"),
(
vec!["--output-allowance", "40000", "--context-window", "32768"],
"output_allowance 40000 leaves no input room in the declared 32768-token context window",
),
] {
common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", NEMOTRON_MODEL])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(extra)
.assert()
.failure()
.stderr(predicates::str::contains(expected));
}
assert!(
requests.lock().expect("request capture lock").is_empty(),
"a refused allowance must not reach the model"
);
assert!(!events_path.exists(), "a refused run records no trace");
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_output_allowance_reports_server_enforcement_from_the_wire() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
let projecting = format!(
r#"default_backend = "nemotron"
[[backends]]
name = "nemotron"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
api = "chat_completions"
[backends.capability.chat_completions]
cognition = true
"#,
server.uri()
);
let unknown = format!(
r#"default_backend = "plain"
[[backends]]
name = "plain"
endpoint = "{}"
model = "plain-model"
kind = "openai"
api = "chat_completions"
[[model_tuning]]
model = "plain-model"
output_allowance = 12000
"#,
server.uri()
);
for (name, config, flag) in [
("projecting", projecting, true),
("unknown", unknown, false),
] {
let config_path = fixture.path().join(format!("{name}.toml"));
let events_path = fixture.path().join(format!("events-{name}.jsonl"));
std::fs::write(&config_path, config).expect("write headless config");
let mut command = common::newt();
command
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"]);
if flag {
command.args(["--output-allowance", "12000"]);
}
command.assert().success();
let bodies = std::mem::take(&mut *requests.lock().expect("request capture lock"));
assert!(!bodies.is_empty(), "{name}: the run reached the model");
for body in &bodies {
assert_eq!(body["max_tokens"], 12000, "{name}: cap is sent");
}
assert_eq!(
contract_from(&events_path)["effective_config"]["output_allowance"],
serde_json::json!({"tokens": 12000, "enforced": "server"}),
"{name}"
);
}
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_with_an_exhausted_run_allowance_refuses_dispatch_before_any_request() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", NEMOTRON_MODEL])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--run-allowance", "0"])
.assert()
.success()
.stdout(predicates::str::contains("run allowance is exhausted"));
assert!(
requests.lock().expect("request capture lock").is_empty(),
"an exhausted run allowance must not reach the model"
);
let lines: Vec<serde_json::Value> = std::fs::read_to_string(&events_path)
.expect("events")
.lines()
.map(|l| serde_json::from_str(l).expect("json line"))
.collect();
let result = lines
.iter()
.find(|r| r["kind"] == "solve_result")
.expect("solve_result");
assert_eq!(result["end_reason"], "Some(RunAllowance)", "{result}");
assert_eq!(result["status"], "incomplete");
let contract = lines
.iter()
.find(|r| r.get("contract_version").is_some())
.expect("contract");
assert_eq!(contract["outcome"], "timeout");
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_run_allowance_is_reported_when_set_and_absent_when_not() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
for (name, extra, expect_key) in [
(
"configured",
vec!["--run-allowance".to_string(), "5".to_string()],
true,
),
("unconfigured", vec![], false),
] {
let events_path = fixture.path().join(format!("events-{name}.jsonl"));
common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", NEMOTRON_MODEL])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.args(&extra)
.assert()
.success();
assert!(
!requests.lock().expect("request capture lock").is_empty(),
"{name}: the run reached the model"
);
requests.lock().expect("request capture lock").clear();
let effective_config = contract_from(&events_path)["effective_config"].clone();
if expect_key {
assert_eq!(
effective_config["run_allowance"],
serde_json::json!(5),
"{name}"
);
} else {
assert!(
effective_config.get("run_allowance").is_none(),
"{name}: no configured allowance must report no key: {effective_config}"
);
}
}
}
#[tokio::test(flavor = "multi_thread")]
async fn a_required_feature_that_cannot_be_supplied_fails_before_inference() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
let seed_path = fixture.path().join("seed.json");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
std::fs::write(&seed_path, r#"{"k": "v"}"#).expect("write scratchpad seed");
let headless = |extra: &[&std::ffi::OsStr]| {
let mut command = common::newt();
command
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", NEMOTRON_MODEL])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.args(extra);
command
};
for (feature, state) in [
("code_search", "unsupported"),
("crew", "unavailable"),
("scratchpad", "unavailable"),
] {
headless(&["--require-feature".as_ref(), feature.as_ref()])
.assert()
.failure()
.stderr(predicates::str::contains(format!(
"required feature `{feature}` is {state}"
)));
}
assert!(
requests.lock().expect("request capture lock").is_empty(),
"a refused requirement must not reach the model"
);
assert!(!events_path.exists(), "a refused run records no trace");
headless(&[
"--require-feature".as_ref(),
"scratchpad".as_ref(),
"--scratchpad-state".as_ref(),
seed_path.as_os_str(),
])
.assert()
.success();
let body = requests
.lock()
.expect("request capture lock")
.pop()
.expect("the admitted run reached the model");
assert!(advertised_tool(&body, "state_set"), "{body}");
let scratchpad = &contract_from(&events_path)["receipt"]["features"]["scratchpad"];
assert_eq!(scratchpad["state"], "instantiated", "{scratchpad}");
assert_eq!(scratchpad["required"], true, "{scratchpad}");
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_scratchpad_state_reaches_wire_and_receipt() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
let seed_path = fixture.path().join("seed.json");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
std::fs::write(&seed_path, r#"{"k": "v"}"#).expect("write scratchpad seed");
common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", NEMOTRON_MODEL])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--scratchpad-state")
.arg(&seed_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
let body = requests
.lock()
.expect("request capture lock")
.pop()
.expect("one captured request");
for tool in ["state_set", "state_get", "state_clear"] {
assert!(advertised_tool(&body, tool), "{tool} advertised: {body}");
}
assert_eq!(body["messages"][0]["role"], "system", "{body}");
assert!(
body["messages"][0]["content"]
.as_str()
.is_some_and(|c| c.contains("<state>\nk: v\n</state>")),
"the seeded state rides message[0]: {body}"
);
let scratchpad = &contract_from(&events_path)["receipt"]["features"]["scratchpad"];
assert_eq!(scratchpad["state"], "instantiated", "{scratchpad}");
assert_eq!(scratchpad["scope"], "fresh");
assert!(
scratchpad["seed"]
.as_str()
.is_some_and(|s| s.starts_with('b')),
"the seed is a content id: {scratchpad}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_prints_the_final_answer_exactly_once_on_every_wire() {
const CLAIM: &str = "FINAL-CLAIM-2372 every check passed";
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(|request: &Request| {
let body: serde_json::Value = serde_json::from_slice(&request.body).unwrap();
if body["stream"].as_bool().unwrap_or(false) {
let frame = serde_json::json!({"choices": [{"delta": {"content": CLAIM}, "finish_reason": "stop"}]});
let sse = format!("data: {frame}\n\ndata: [DONE]\n\n");
return ResponseTemplate::new(200).set_body_raw(sse.into_bytes(), "text/event-stream");
}
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"choices": [{"message": {"role": "assistant", "content": CLAIM}, "finish_reason": "stop"}]
}))
})
.mount(&server)
.await;
Mock::given(method("POST"))
.and(path("/v1/messages"))
.respond_with(|_request: &Request| {
let frames = [
serde_json::json!({"type": "message_start", "message": {"model": "m", "usage": {"input_tokens": 5}}}),
serde_json::json!({"type": "content_block_start", "index": 0, "content_block": {"type": "text"}}),
serde_json::json!({"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": CLAIM}}),
serde_json::json!({"type": "content_block_stop", "index": 0}),
serde_json::json!({"type": "message_delta", "delta": {"stop_reason": "end_turn"}, "usage": {"output_tokens": 4}}),
serde_json::json!({"type": "message_stop"}),
];
let body: String = frames.iter().map(|f| format!("data: {f}\n\n")).collect();
ResponseTemplate::new(200).set_body_raw(body.into_bytes(), "text/event-stream")
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
for kind in ["openai", "anthropic"] {
let output = common::newt()
.env_remove("NEWT_TEAM")
.env_remove("NEWT_ANTHROPIC_STREAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", "m"])
.args(["--backend-kind", kind])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.args(["--max-rounds", "1"])
.output()
.expect("run newt headless");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"{kind}: {}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(stdout.matches(CLAIM).count(), 1, "{kind}: {stdout}");
assert_eq!(stdout.matches("## Observed").count(), 1, "{kind}: {stdout}");
}
let output = common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", "m"])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(fixture.path())
.args(["--max-rounds", "1"])
.output()
.expect("run newt headless");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!output.status.success(),
"a directory is not an events file"
);
assert_eq!(stdout.matches("▸ ## Observed").count(), 1, "{stdout}");
assert_eq!(stdout.matches(CLAIM).count(), 1, "{stdout}");
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_prints_a_harness_written_reply_as_a_notice_not_a_claim() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(|request: &Request| {
let body: serde_json::Value = serde_json::from_slice(&request.body).unwrap();
if body["stream"].as_bool().unwrap_or(false) {
let frame = serde_json::json!({"choices": [{"delta": {"content": ""}, "finish_reason": "stop"}]});
let sse = format!("data: {frame}\n\ndata: [DONE]\n\n");
return ResponseTemplate::new(200).set_body_raw(sse.into_bytes(), "text/event-stream");
}
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"choices": [{"message": {"role": "assistant", "content": ""}, "finish_reason": "stop"}]
}))
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
let output = common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", "m"])
.args(["--backend-kind", "openai"])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.args(["--max-rounds", "1"])
.output()
.expect("run newt headless");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("⚠ newt: ## Observed"),
"the harness text is a notice: {stdout}"
);
assert!(
!stdout.contains("▸ (model returned"),
"never a claim: {stdout}"
);
let report_start = stdout.find("## Observed").unwrap();
let report_end = stdout[report_start..].find("\n{").unwrap() + report_start;
let report = &stdout[report_start..report_end];
assert!(report.contains("(model returned an empty response"));
assert!(newt_core::agentic::model_reply_for_history(report)
.trim()
.is_empty());
let result = stdout
.lines()
.filter_map(|line| serde_json::from_str::<serde_json::Value>(line).ok())
.find(|event| event["kind"] == "solve_result")
.unwrap();
assert_eq!(
result["handback"]["model_reply_present"], false,
"a host notice is not a model reply"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn explicit_config_still_honors_cli_backend_override() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let stale_server = MockServer::start().await;
let stale_requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: stale_requests.clone(),
})
.mount(&stale_server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let config_path = fixture.path().join("benchmark.toml");
let instruction_path = fixture.path().join("instruction.md");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(
&config_path,
format!(
r#"default_backend = "stale"
[[backends]]
name = "stale"
endpoint = "{}"
model = "stale-model"
kind = "openai"
"#,
stale_server.uri()
),
)
.expect("write explicit headless config");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
common::newt()
.env_remove("NEWT_TEAM")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", "operator-model"])
.args(["--backend-kind", "openai"])
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
let requests = requests.lock().expect("request capture lock");
assert_eq!(requests.len(), 1, "the CLI endpoint served the turn");
for request in requests.iter() {
assert_eq!(request["model"], "operator-model");
}
drop(requests);
assert!(
stale_requests
.lock()
.expect("stale request lock")
.is_empty(),
"the explicit file's stale backend must not receive the turn"
);
let contract = contract_from(&events_path);
assert_eq!(contract["requested_model"], "operator-model");
assert_eq!(contract["backend"]["name"], "cli");
assert_eq!(contract["timing"]["gen_tokens"], 7, "{contract}");
}
#[tokio::test(flavor = "multi_thread")]
async fn unsupported_chat_cognition_is_default_on_wire_and_contract() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: requests.clone(),
})
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let config_path = fixture.path().join("benchmark.toml");
let instruction_path = fixture.path().join("instruction.md");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(
&config_path,
format!(
r#"default_backend = "unknown-chat"
[[backends]]
name = "unknown-chat"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
api = "chat_completions"
"#,
server.uri()
),
)
.expect("write explicit headless config");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
common::newt()
.env_remove("NEWT_TEAM")
.args(["--cognition", "meticulous"])
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
let requests = requests.lock().expect("request capture lock");
assert_eq!(requests.len(), 1);
for request in requests.iter() {
assert!(
request["max_tokens"]
.as_u64()
.is_some_and(|cap| cap > 0 && cap <= 16_384),
"#2782: generation is bounded independently of cognition"
);
assert!(request.get("chat_template_kwargs").is_none());
}
drop(requests);
let contract = contract_from(&events_path);
assert_eq!(contract["effective_config"]["cognition"], "default");
}
const CAP_ROUNDS: usize = 11;
const EARLY_WRITES: usize = 3;
fn solve_result_from(path: &std::path::Path) -> serde_json::Value {
let raw = std::fs::read_to_string(path).expect("read headless events");
let mut results = raw
.lines()
.map(|line| serde_json::from_str::<serde_json::Value>(line).expect("event line is JSON"))
.filter(|record| record.get("kind").and_then(|k| k.as_str()) == Some("solve_result"));
let result = results.next().expect("one solve_result record");
assert!(results.next().is_none(), "exactly one solve_result record");
result
}
struct WritesEarlyThenGrindsReadOnly {
round: AtomicUsize,
rounds_served: Arc<AtomicUsize>,
}
impl Respond for WritesEarlyThenGrindsReadOnly {
fn respond(&self, request: &Request) -> ResponseTemplate {
let body: serde_json::Value =
serde_json::from_slice(&request.body).expect("chat request is JSON");
if body.get("tools").is_none() {
return ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": NEMOTRON_MODEL,
"choices": [{
"message": {"role": "assistant", "content": "I made the three edits and verified them."},
"finish_reason": "stop"
}]
}));
}
let n = self.rounds_served.fetch_add(1, Ordering::SeqCst);
let _ = self.round.fetch_add(1, Ordering::SeqCst);
let call = if n < EARLY_WRITES {
serde_json::json!({
"id": format!("write_{n}"),
"type": "function",
"function": {
"name": "write_file",
"arguments": serde_json::to_string(&serde_json::json!({
"path": format!("src/produced_{n}.rs"),
"content": format!("pub const PRODUCED_{n}: u32 = {n};\n"),
})).expect("write args serialize")
}
})
} else {
serde_json::json!({
"id": format!("read_{n}"),
"type": "function",
"function": {
"name": "read_file",
"arguments": serde_json::to_string(&serde_json::json!({
"path": format!("src/seed_{n}.rs"),
})).expect("read args serialize")
}
})
};
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": NEMOTRON_MODEL,
"choices": [{
"message": {"role": "assistant", "content": null, "tool_calls": [call]},
"finish_reason": "tool_calls"
}]
}))
}
}
#[tokio::test(flavor = "multi_thread")]
async fn round_cap_exit_is_not_reported_as_a_completed_run() {
assert_round_cap_exit(false).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn explicit_zero_grace_stops_fresh_evidence_at_the_round_cap() {
assert_round_cap_exit(true).await;
}
async fn assert_round_cap_exit(hard_cap: bool) {
let cap_rounds = if hard_cap { 8 } else { CAP_ROUNDS };
let server = MockServer::start().await;
let rounds_served = Arc::new(AtomicUsize::new(0));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(WritesEarlyThenGrindsReadOnly {
round: AtomicUsize::new(0),
rounds_served: rounds_served.clone(),
})
.mount(&server)
.await;
let workspace = tempfile::tempdir().expect("temporary headless workspace");
let src = workspace.path().join("src");
std::fs::create_dir_all(&src).expect("workspace src dir");
for n in 0..(cap_rounds + 4) {
std::fs::write(
src.join(format!("seed_{n}.rs")),
if hard_cap {
format!("pub const SEED_{n}: u32 = {n};\n")
} else {
"pub const OBSERVED: u32 = 0;\n".to_string()
},
)
.expect("write seed file");
}
let round_policy = if hard_cap {
"\n[tui]\nworkflow_grace_rounds = 0\n"
} else {
""
};
let config_path = workspace.path().join("headless.toml");
let instruction_path = workspace.path().join("instruction.md");
let events_path = workspace.path().join("events.jsonl");
std::fs::write(
&config_path,
format!(
r#"default_backend = "capped"
[[backends]]
name = "capped"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
{round_policy}
"#,
server.uri()
),
)
.expect("write headless config");
std::fs::write(
&instruction_path,
"Add the three produced constants, then verify them.\n",
)
.expect("write headless instruction");
common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", &cap_rounds.to_string()])
.assert()
.success();
let result = solve_result_from(&events_path);
let served = rounds_served.load(Ordering::SeqCst);
assert_eq!(
served, cap_rounds,
"the scripted model must have served exactly {cap_rounds} tool rounds; \
served {served} — the replay did not run the trajectory it claims to"
);
assert_eq!(
result["tool_calls"], cap_rounds as u64,
"the harness must have dispatched every scripted round: {result}"
);
assert_eq!(
result["write_calls"], EARLY_WRITES as u64,
"the early-write half of the shape must have happened — without it this \
is a generic capped run, not the write-complete-then-grind case: {result}"
);
let writes_ok = result["trajectory"]
.as_array()
.expect("trajectory is an array")
.iter()
.filter(|e| e["tool"] == "write_file" && e["ok"] == true)
.count();
assert_eq!(
writes_ok, EARLY_WRITES,
"the early writes must have SUCCEEDED, not merely been attempted: {result}"
);
let reads_ok = result["trajectory"]
.as_array()
.expect("trajectory is an array")
.iter()
.filter(|e| e["tool"] == "read_file" && e["ok"] == true)
.count();
assert_eq!(
reads_ok,
cap_rounds - EARLY_WRITES,
"every distinct-path tail read must execute successfully: {result}"
);
assert_eq!(
result["calls_after_last_write"],
(cap_rounds - EARLY_WRITES) as u64,
"the run spent its whole tail after the work was done; that must be a \
value a gate can assert, not prose in the reply: {result}"
);
assert_eq!(
result["end_reason"], "Some(RoundCap)",
"fixture must reproduce a cap exit, else the honesty assertion is vacuous: {result}"
);
assert_eq!(
result["status"], "incomplete",
"a run that ended at the tool-round cap must report itself incomplete \
— end_reason says RoundCap on the same line: {result}"
);
let contract = contract_from(&events_path);
assert_eq!(
contract["outcome"], "timeout",
"a cap exit must file in a bucket the bench's closed enum can parse \
AND that excludes it from capability scoring; which wall it hit is \
`status` and `end_reason`'s to report: {contract}"
);
}
async fn headless_against_stream(stream: String) -> (usize, serde_json::Value, serde_json::Value) {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ResponseTemplate::new(200).set_body_raw(stream, "text/event-stream"))
.mount(&server)
.await;
let workspace = tempfile::tempdir().expect("temporary headless workspace");
let config_path = workspace.path().join("headless.toml");
let instruction_path = workspace.path().join("instruction.md");
let events_path = workspace.path().join("events.jsonl");
std::fs::write(
&config_path,
format!(
r#"default_backend = "strict"
[[backends]]
name = "strict"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
"#,
server.uri()
),
)
.expect("write headless config");
std::fs::write(&instruction_path, "Read the seed file.\n").expect("write headless instruction");
let _ = common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.assert();
let posts = server
.received_requests()
.await
.expect("journal")
.into_iter()
.filter(|request| request.method.as_str() == "POST")
.count();
(
posts,
solve_result_from(&events_path),
contract_from(&events_path),
)
}
fn streamed_read_file_call(id: &str) -> String {
[
format!(
r#"{{"choices":[{{"delta":{{"tool_calls":[{{"index":0,{id}"type":"function","function":{{"name":"read_file","arguments":"{{}}"}}}}]}}}}]}}"#
),
r#"{"choices":[{"delta":{},"finish_reason":"tool_calls"}]}"#.to_string(),
"[DONE]".to_string(),
]
.iter()
.map(|frame| format!("data: {frame}\n\n"))
.collect()
}
fn streamed_lifecycle_call(args_json: &str) -> String {
let escaped = args_json.replace('\\', "\\\\").replace('"', "\\\"");
[
format!(
r#"{{"choices":[{{"delta":{{"tool_calls":[{{"index":0,"id":"call_1","type":"function","function":{{"name":"lifecycle","arguments":"{escaped}"}}}}]}}}}]}}"#
),
r#"{"choices":[{"delta":{},"finish_reason":"tool_calls"}]}"#.to_string(),
"[DONE]".to_string(),
]
.iter()
.map(|frame| format!("data: {frame}\n\n"))
.collect()
}
async fn headless_lifecycle_build_attempt(
scratch_field: Option<&str>,
) -> (tempfile::TempDir, serde_json::Value) {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ResponseTemplate::new(200).set_body_raw(
streamed_lifecycle_call(r#"{"phase":"test","action":"build"}"#),
"text/event-stream",
))
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let workspace = fixture.path().join("workspace");
let ordinary_temp = fixture.path().join("ordinary-temp");
std::fs::create_dir(&workspace).expect("workspace");
std::fs::create_dir(&ordinary_temp).expect("ordinary temp");
std::fs::write(workspace.as_path().join("Cargo.toml"), "").expect("write Cargo.toml marker");
let config_path = workspace.as_path().join("headless.toml");
let instruction_path = workspace.as_path().join("instruction.md");
let events_path = workspace.as_path().join("events.jsonl");
std::fs::write(
&config_path,
format!(
r#"default_backend = "strict"
[[backends]]
name = "strict"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
"#,
server.uri()
),
)
.expect("write headless config");
if let Some(field) = scratch_field {
let configured = fixture.path().join("configured-scratch");
let config = std::fs::read_to_string(&config_path).unwrap();
let value = toml::Value::String(configured.to_string_lossy().into_owned());
std::fs::write(
&config_path,
format!("{config}\n[scratch]\n{field} = {value}\n"),
)
.unwrap();
}
std::fs::write(&instruction_path, "Verify the change builds.\n")
.expect("write headless instruction");
let _ = common::newt()
.env_remove("NEWT_TEAM")
.env_remove("NEWT_SCRATCH_DIR")
.env_remove("NEWT_BUILD_SCRATCH_DIR")
.env("TMPDIR", &ordinary_temp)
.env("TEMP", &ordinary_temp)
.env("TMP", &ordinary_temp)
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.as_path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert();
let result = solve_result_from(&events_path);
(fixture, result)
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_lifecycle_action_build_runs_ungated_by_default_caveats() {
let (_fixture, result) = headless_lifecycle_build_attempt(None).await;
let trajectory = result["trajectory"].as_array().expect("trajectory");
assert!(
!trajectory.is_empty(),
"at least one dispatched call: {result}"
);
for entry in trajectory {
assert_eq!(entry["tool"], "lifecycle", "{entry}");
assert_eq!(entry["ok"], false, "{entry}");
}
assert_ne!(trajectory[0]["execution"], "denied", "{}", trajectory[0]);
#[cfg(target_os = "linux")]
assert_eq!(trajectory[0]["execution"], "failed", "{}", trajectory[0]);
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_scratch_overrides_do_not_authorize_external_build_partitions() {
for field in ["dir", "build_dir"] {
let (fixture, result) = headless_lifecycle_build_attempt(Some(field)).await;
let trajectory = result["trajectory"].as_array().expect("trajectory");
assert!(!trajectory.is_empty(), "{field}: {result}");
assert_eq!(trajectory[0]["tool"], "lifecycle", "{field}: {result}");
assert_eq!(trajectory[0]["execution"], "denied", "{field}: {result}");
assert!(!fixture.path().join("configured-scratch").exists());
assert!(!fixture.path().join("workspace/target").exists());
}
}
#[tokio::test(flavor = "multi_thread")]
async fn a_strictly_rejected_stream_files_as_model_error() {
let (posts, result, contract) =
headless_against_stream(streamed_read_file_call(r#""id":7,"#)).await;
assert_eq!(posts, 1, "exactly one POST: the rejection is not retried");
assert_eq!(result["tool_calls"], 0, "nothing ran: {result}");
assert_eq!(result["end_reason"], "Some(Failed)", "{result}");
assert_eq!(contract["outcome"], "model_error", "{contract}");
}
#[tokio::test(flavor = "multi_thread")]
async fn a_streamed_idless_call_is_re_asked_then_files_as_model_error() {
let (posts, result, contract) = headless_against_stream(streamed_read_file_call("")).await;
assert_eq!(posts, 3, "two re-asks, then the third id-less batch aborts");
let trajectory = result["trajectory"].as_array().expect("trajectory");
assert_eq!(trajectory.len(), 2, "one marker per re-ask: {result}");
assert!(
trajectory
.iter()
.all(|e| e["tool"] == "(rejected tool-call batch)" && e["ok"] == false),
"nothing was dispatched: {result}"
);
assert_eq!(contract["outcome"], "model_error", "{contract}");
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_reports_verification_off_where_the_loop_has_no_gate() {
for (api, expected) in [("chat", "result_aware"), ("responses", "off")] {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(CaptureThenFinish {
requests: Arc::new(Mutex::new(Vec::new())),
})
.mount(&server)
.await;
Mock::given(method("POST"))
.and(path("/v1/responses"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"id": "resp_1", "status": "completed", "model": NEMOTRON_MODEL,
"output": [{"type": "message", "id": "msg_1", "role": "assistant",
"status": "completed",
"content": [{"type": "output_text", "text": "done", "annotations": []}]}]
})))
.mount(&server)
.await;
let fixture = tempfile::tempdir().expect("temporary headless fixture");
let instruction_path = fixture.path().join("instruction.md");
let events_path = fixture.path().join("events.jsonl");
std::fs::write(&instruction_path, "Finish without calling a tool.\n")
.expect("write headless instruction");
common::newt()
.env_remove("NEWT_TEAM")
.env("NEWT_SELF_VERIFY", "1")
.env("NEWT_VERIFY_OUTCOMES", "1")
.args(["--backend-endpoint", &server.uri()])
.args(["--backend-model", NEMOTRON_MODEL])
.args(["--backend-kind", "openai"])
.args(["--backend-api", api])
.args(["headless", "--cwd"])
.arg(fixture.path())
.arg("--instruction-file")
.arg(&instruction_path)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
let verification = &contract_from(&events_path)["receipt"]["verification"];
assert_eq!(verification["mode"], expected, "{api}: {verification}");
}
}
fn usage_sse_reply(measured: bool) -> ResponseTemplate {
let mut frames = vec![serde_json::json!({
"model": NEMOTRON_MODEL,
"choices": [{"delta": {"role": "assistant", "content": "done"}, "finish_reason": "stop"}]
})
.to_string()];
if measured {
frames.push(
serde_json::json!({"choices": [], "usage": {"prompt_tokens": 32, "completion_tokens": 12}})
.to_string(),
);
}
frames.push("[DONE]".to_string());
let body: String = frames
.iter()
.map(|frame| format!("data: {frame}\n\n"))
.collect();
ResponseTemplate::new(200).set_body_raw(body, "text/event-stream")
}
fn run_usage_solve(
server: &MockServer,
workspace: &std::path::Path,
pricing: bool,
events: bool,
) -> String {
let config_path = workspace.join("headless.toml");
let instruction_path = workspace.join("instruction.md");
let mut config = format!(
r#"default_backend = "usage"
[[backends]]
name = "usage"
endpoint = "{}"
model = "{NEMOTRON_MODEL}"
kind = "openai"
"#,
server.uri()
);
if pricing {
config.push_str(&format!(
"\n[pricing.overrides.\"{NEMOTRON_MODEL}\"]\ninput_usd_per_1k = 1.0\noutput_usd_per_1k = 1.0\n"
));
}
std::fs::write(&config_path, config).expect("write headless config");
std::fs::write(&instruction_path, "Say done.\n").expect("write headless instruction");
let mut command = common::newt();
command
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace)
.arg("--instruction-file")
.arg(&instruction_path);
if events {
command.arg("--events").arg(workspace.join("events.jsonl"));
}
let output = command.output().expect("newt headless runs");
String::from_utf8(output.stdout).expect("stdout is UTF-8")
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_reports_per_attempt_usage_and_a_verifiable_attempt_ledger() {
use newt_core::attempts::AttemptRecord;
use newt_core::event_journal::{verify_chain, JournalLine};
for measured in [true, false] {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(usage_sse_reply(measured))
.mount(&server)
.await;
let workspace = tempfile::tempdir().expect("temporary headless workspace");
run_usage_solve(&server, workspace.path(), measured, true);
let posts = server.received_requests().await.expect("journal").len() as u64;
assert!(posts > 0, "measured={measured}: the run reached the model");
let events_path = workspace.path().join("events.jsonl");
let result = solve_result_from(&events_path);
let usage = &result["usage"];
assert_eq!(usage["attempts"], posts, "measured={measured}: {usage}");
if measured {
assert_eq!(usage["in_tokens"], 32 * posts, "{usage}");
assert_eq!(usage["out_tokens"], 12 * posts, "{usage}");
assert_eq!(usage["usage_missing"], 0, "{usage}");
assert_eq!(usage["usage_complete"], true, "{usage}");
let cost = usage["cost_usd"]
.as_f64()
.expect("a complete, priced run has a cost");
assert!((cost - 0.044 * posts as f64).abs() < 1e-9, "{usage}");
} else {
assert_eq!(usage["in_tokens"], 0, "{usage}");
assert_eq!(usage["usage_missing"], posts, "{usage}");
assert_eq!(usage["usage_complete"], false, "{usage}");
assert!(
usage.get("cost_usd").is_none(),
"unknown is not zero: {usage}"
);
}
let lines: Vec<JournalLine<AttemptRecord>> = std::fs::read_to_string(&events_path)
.expect("read headless events")
.lines()
.map(|line| {
serde_json::from_str::<serde_json::Value>(line).expect("event line is JSON")
})
.filter(|record| record["kind"] == "attempt")
.map(|record| {
serde_json::from_value(record).expect("an attempt line is a journal line")
})
.collect();
let head = usage["ledger_head"]
.as_str()
.expect("--events carries the head");
assert_eq!(
verify_chain(&lines, Some(head)),
vec![],
"measured={measured}"
);
let attempts: std::collections::BTreeSet<_> =
lines.iter().map(|line| line.node.payload().id).collect();
assert_eq!(attempts.len() as u64, posts, "one attempt id per POST");
}
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(usage_sse_reply(true))
.mount(&server)
.await;
let workspace = tempfile::tempdir().expect("temporary headless workspace");
let stdout = run_usage_solve(&server, workspace.path(), false, false);
let records: Vec<serde_json::Value> = stdout
.lines()
.filter_map(|line| serde_json::from_str(line).ok())
.collect();
assert!(
records.iter().all(|record| record["kind"] != "attempt"),
"no --events, no lines"
);
let result = records
.iter()
.find(|record| record["kind"] == "solve_result")
.expect("a solve_result line on stdout");
assert!(result["usage"]["attempts"].as_u64() > Some(0), "{result}");
assert!(result["usage"].get("ledger_head").is_none(), "{result}");
}
#[path = "headless_cli/cognition.rs"]
mod cognition;
struct WriteThenFail {
sequence: AtomicUsize,
}
impl Respond for WriteThenFail {
fn respond(&self, _request: &Request) -> ResponseTemplate {
if self.sequence.fetch_add(1, Ordering::SeqCst) > 0 {
return ResponseTemplate::new(500).set_body_string("upstream exploded");
}
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": "m",
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "w0",
"type": "function",
"function": {
"name": "write_file",
"arguments": "{\"path\":\"out.txt\",\"content\":\"partial\\n\"}"
}
}]
},
"finish_reason": "tool_calls"
}]
}))
}
}
#[tokio::test(flavor = "multi_thread")]
async fn a_run_that_fails_after_a_write_hands_back_what_it_changed() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(WriteThenFail {
sequence: AtomicUsize::new(0),
})
.mount(&server)
.await;
let control = tempfile::tempdir().expect("control dir outside the workspace");
let workspace = tempfile::tempdir().expect("temporary headless workspace");
let git = |args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(workspace.path())
.output()
.expect("git")
.status
.success());
};
git(&["init", "-q"]);
std::fs::write(workspace.path().join("dirty-before.txt"), "x\n").expect("pre-existing dirt");
let config_path = control.path().join("cfg.toml");
std::fs::write(
&config_path,
format!(
"default_backend = \"b\"\n\n[[backends]]\nname = \"b\"\nendpoint = \"{}\"\nmodel = \"m\"\nkind = \"openai\"\n",
server.uri()
),
)
.expect("write config");
let instruction = control.path().join("task.md");
std::fs::write(&instruction, "Write out.txt.\n").expect("write instruction");
let events_path = control.path().join("events.jsonl");
common::newt()
.env_remove("NEWT_TEAM")
.env("NEWT_HTTP_MAX_RETRIES", "0")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "4"])
.assert()
.failure();
let result: serde_json::Value = std::fs::read_to_string(&events_path)
.expect("read headless events")
.lines()
.map(|l| serde_json::from_str::<serde_json::Value>(l).expect("event line is JSON"))
.find(|r| r["kind"] == "solve_result")
.expect("a solve_result line");
assert_eq!(result["status"], "failed", "{result}");
let handback = &result["handback"];
assert_eq!(
handback["files_changed"],
serde_json::json!(["out.txt"]),
"{result}"
);
assert_eq!(handback["files_changed_source"], "git_status_delta");
assert_eq!(handback["files_changed_truncated"], false);
assert_eq!(handback["model_reply_present"], false);
assert!(handback["end_reason"].is_string(), "{handback}");
assert_eq!(
handback["uncommitted_files"],
serde_json::json!(["dirty-before.txt", "out.txt"]),
"{result}"
);
assert_eq!(handback["uncommitted_files_source"], "git_status");
assert!(handback.get("commits").is_none(), "{handback}");
}
async fn handback_from_a_no_op_run(
server: &MockServer,
workspace: &std::path::Path,
control: &std::path::Path,
) -> serde_json::Value {
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"choices": [{"message": {"role": "assistant", "content": "done, nothing to change"}, "finish_reason": "stop"}]
})))
.mount(server)
.await;
let config_path = control.join("cfg.toml");
std::fs::write(
&config_path,
format!(
"default_backend = \"b\"\n\n[[backends]]\nname = \"b\"\nendpoint = \"{}\"\nmodel = \"m\"\nkind = \"openai\"\n",
server.uri()
),
)
.expect("write config");
let instruction = control.join("task.md");
std::fs::write(&instruction, "Just answer, don't touch anything.\n")
.expect("write instruction");
let events_path = control.join("events.jsonl");
common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace)
.arg("--instruction-file")
.arg(&instruction)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
std::fs::read_to_string(&events_path)
.expect("read headless events")
.lines()
.map(|l| serde_json::from_str::<serde_json::Value>(l).expect("event line is JSON"))
.find(|r| r["kind"] == "solve_result")
.expect("a solve_result line")["handback"]
.clone()
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_reports_unavailable_off_a_non_git_workspace() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("non-git workspace");
let handback = handback_from_a_no_op_run(&server, workspace.path(), control.path()).await;
assert!(handback["uncommitted_files"].is_null(), "{handback}");
assert_eq!(handback["uncommitted_files_source"], "unavailable");
assert!(handback.get("commits").is_none(), "{handback}");
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_reports_a_clean_repo_when_the_run_touched_nothing() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("git workspace");
let git = |args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(workspace.path())
.output()
.expect("git")
.status
.success());
};
git(&["init", "-q"]);
git(&["config", "user.email", "t@example.com"]);
git(&["config", "user.name", "t"]);
std::fs::write(workspace.path().join("a.txt"), "one\n").expect("seed file");
git(&["add", "a.txt"]);
git(&["commit", "-q", "-m", "first"]);
let handback = handback_from_a_no_op_run(&server, workspace.path(), control.path()).await;
assert_eq!(
handback["uncommitted_files"],
serde_json::json!([]),
"{handback}"
);
assert_eq!(handback["uncommitted_files_source"], "git_status");
assert!(handback.get("commits").is_none(), "{handback}");
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_reports_nested_repos_at_a_bare_multi_repo_root() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("bare multi-repo root");
let git = |dir: &std::path::Path, args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(dir)
.output()
.expect("git")
.status
.success());
};
let repo_a = workspace.path().join("repoA");
std::fs::create_dir_all(&repo_a).unwrap();
git(&repo_a, &["init", "-q"]);
git(&repo_a, &["config", "user.email", "t@example.com"]);
git(&repo_a, &["config", "user.name", "t"]);
std::fs::write(repo_a.join("a.txt"), "one\n").unwrap();
git(&repo_a, &["add", "a.txt"]);
git(&repo_a, &["commit", "-q", "-m", "init"]);
std::fs::write(repo_a.join("a.txt"), "one\ntwo\n").unwrap(); let repo_b = workspace.path().join("repoB");
std::fs::create_dir_all(&repo_b).unwrap();
git(&repo_b, &["init", "-q"]);
let handback = handback_from_a_no_op_run(&server, workspace.path(), control.path()).await;
assert_eq!(
handback["uncommitted_files_source"], "nested-repos",
"{handback}"
);
assert_eq!(
handback["uncommitted_files"],
serde_json::json!(["repoA/a.txt"]),
"{handback}"
);
let by_repo = handback["uncommitted_files_by_repo"]
.as_array()
.expect("per-repo breakdown present");
assert!(
by_repo
.iter()
.any(|r| r["repo"] == "repoA" && r["files"] == serde_json::json!(["a.txt"])),
"{handback}"
);
assert!(
by_repo
.iter()
.any(|r| r["repo"] == "repoB" && r["files"] == serde_json::json!([])),
"{handback}"
);
assert!(
handback.get("uncommitted_files_unprobed").is_none(),
"both repos probed cleanly: {handback}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_at_a_real_repo_root_is_unaffected_by_nested_repo_support() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("git workspace");
let git = |args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(workspace.path())
.output()
.expect("git")
.status
.success());
};
git(&["init", "-q"]);
git(&["config", "user.email", "t@example.com"]);
git(&["config", "user.name", "t"]);
std::fs::write(workspace.path().join("a.txt"), "one\n").expect("seed file");
git(&["add", "a.txt"]);
git(&["commit", "-q", "-m", "first"]);
let handback = handback_from_a_no_op_run(&server, workspace.path(), control.path()).await;
assert_eq!(
handback["files_changed_source"], "git_status_delta",
"{handback}"
);
assert_eq!(
handback["uncommitted_files_source"], "git_status",
"{handback}"
);
assert!(
handback.get("files_changed_by_repo").is_none(),
"{handback}"
);
assert!(
handback.get("files_changed_unprobed").is_none(),
"{handback}"
);
assert!(
handback.get("uncommitted_files_by_repo").is_none(),
"{handback}"
);
assert!(
handback.get("uncommitted_files_unprobed").is_none(),
"{handback}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_at_a_repo_subdirectory_reports_only_its_nested_repo_never_the_enclosing_one() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let outer = tempfile::tempdir().expect("outer repo");
let git = |dir: &std::path::Path, args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(dir)
.output()
.expect("git")
.status
.success());
};
git(outer.path(), &["init", "-q"]);
git(outer.path(), &["config", "user.email", "t@example.com"]);
git(outer.path(), &["config", "user.name", "t"]);
std::fs::write(outer.path().join("outer.txt"), "one\n").unwrap();
git(outer.path(), &["add", "outer.txt"]);
git(outer.path(), &["commit", "-q", "-m", "outer init"]);
std::fs::write(outer.path().join("outer.txt"), "one\ntwo\n").unwrap();
let workspace = outer.path().join("workspace");
std::fs::create_dir_all(&workspace).unwrap();
let inner = workspace.join("inner");
std::fs::create_dir_all(&inner).unwrap();
git(&inner, &["init", "-q"]);
git(&inner, &["config", "user.email", "t@example.com"]);
git(&inner, &["config", "user.name", "t"]);
std::fs::write(inner.join("i.txt"), "one\n").unwrap();
git(&inner, &["add", "i.txt"]);
git(&inner, &["commit", "-q", "-m", "inner init"]);
std::fs::write(inner.join("i.txt"), "one\ntwo\n").unwrap();
let handback = handback_from_a_no_op_run(&server, &workspace, control.path()).await;
let dump = handback.to_string();
assert!(
!dump.contains("outer.txt"),
"outer.txt must appear in no field: {handback}"
);
assert_eq!(
handback["uncommitted_files_source"], "git_status_subtree",
"{handback}"
);
assert_eq!(
handback["uncommitted_files"],
serde_json::json!(["inner/i.txt"]),
"{handback}"
);
assert_eq!(
handback["files_changed_source"], "git_status_subtree",
"{handback}"
);
}
#[tokio::test(flavor = "multi_thread")]
#[cfg(unix)]
async fn handback_never_probes_a_symlinked_first_level_dir_pointing_outside() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("bare workspace root");
let outside = tempfile::tempdir().expect("outside repo");
let git = |dir: &std::path::Path, args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(dir)
.output()
.expect("git")
.status
.success());
};
git(outside.path(), &["init", "-q"]);
git(outside.path(), &["config", "user.email", "t@example.com"]);
git(outside.path(), &["config", "user.name", "t"]);
std::fs::write(outside.path().join("secret.txt"), "leak\n").unwrap();
git(outside.path(), &["add", "secret.txt"]);
git(outside.path(), &["commit", "-q", "-m", "init"]);
std::fs::write(outside.path().join("secret.txt"), "leak\nmore\n").unwrap();
std::os::unix::fs::symlink(outside.path(), workspace.path().join("ext")).expect("symlink");
let handback = handback_from_a_no_op_run(&server, workspace.path(), control.path()).await;
let dump = handback.to_string();
assert!(
!dump.contains("secret.txt"),
"a symlinked first-level dir must never be probed: {handback}"
);
assert_eq!(
handback["uncommitted_files_source"], "unavailable",
"no real nested repo exists (the symlink is skipped), so this stays \
unavailable exactly like an empty bare folder: {handback}"
);
}
#[tokio::test(flavor = "multi_thread")]
#[cfg(unix)]
async fn handback_at_a_symlinked_repo_root_takes_the_root_branch() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let real = tempfile::tempdir().expect("real repo root");
let git = |args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(real.path())
.output()
.expect("git")
.status
.success());
};
git(&["init", "-q"]);
git(&["config", "user.email", "t@example.com"]);
git(&["config", "user.name", "t"]);
std::fs::write(real.path().join("a.txt"), "one\n").unwrap();
git(&["add", "a.txt"]);
git(&["commit", "-q", "-m", "init"]);
std::fs::write(real.path().join("a.txt"), "one\ntwo\n").unwrap();
let link = real
.path()
.parent()
.expect("tempdir has a parent")
.join(format!(
"symlink-{}",
real.path().file_name().unwrap().to_string_lossy()
));
std::os::unix::fs::symlink(real.path(), &link).expect("symlink");
let handback = handback_from_a_no_op_run(&server, &link, control.path()).await;
std::fs::remove_file(&link).ok();
assert_eq!(
handback["uncommitted_files_source"], "git_status",
"a symlinked spelling of a real repo root must still take the root \
branch, not the nested-repos path: {handback}"
);
assert!(
handback.get("uncommitted_files_by_repo").is_none(),
"{handback}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_at_a_repo_subdirectory_reports_only_the_subtree_edit_with_a_distinct_source() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let repo = tempfile::tempdir().expect("repo root");
let git = |args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(repo.path())
.output()
.expect("git")
.status
.success());
};
git(&["init", "-q"]);
git(&["config", "user.email", "t@example.com"]);
git(&["config", "user.name", "t"]);
let crate_dir = repo.path().join("crate");
std::fs::create_dir_all(&crate_dir).unwrap();
std::fs::write(repo.path().join("root.txt"), "one\n").unwrap();
std::fs::write(crate_dir.join("lib.rs"), "one\n").unwrap();
git(&["add", "-A"]);
git(&["commit", "-q", "-m", "init"]);
std::fs::write(repo.path().join("root.txt"), "one\ntwo\n").unwrap();
std::fs::write(crate_dir.join("lib.rs"), "one\ntwo\n").unwrap();
let handback = handback_from_a_no_op_run(&server, &crate_dir, control.path()).await;
assert_eq!(
handback["uncommitted_files_source"], "git_status_subtree",
"{handback}"
);
assert_eq!(
handback["uncommitted_files"],
serde_json::json!(["lib.rs"]),
"workspace-relative, no crate/ prefix, and never root.txt: {handback}"
);
let dump = handback.to_string();
assert!(
!dump.contains("root.txt"),
"the outside-the-workspace edit must appear in no field: {handback}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn handback_stays_sane_under_a_detached_head() {
let server = MockServer::start().await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("git workspace");
let git = |args: &[&str]| {
assert!(std::process::Command::new("git")
.args(args)
.current_dir(workspace.path())
.output()
.expect("git")
.status
.success());
};
git(&["init", "-q"]);
git(&["config", "user.email", "t@example.com"]);
git(&["config", "user.name", "t"]);
std::fs::write(workspace.path().join("a.txt"), "one\n").expect("seed file");
git(&["add", "a.txt"]);
git(&["commit", "-q", "-m", "first"]);
let head = std::process::Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(workspace.path())
.output()
.expect("rev-parse");
let head = String::from_utf8_lossy(&head.stdout).trim().to_string();
git(&["checkout", "-q", "--detach", &head]);
let handback = handback_from_a_no_op_run(&server, workspace.path(), control.path()).await;
assert_eq!(
handback["uncommitted_files"],
serde_json::json!([]),
"{handback}"
);
assert_eq!(handback["uncommitted_files_source"], "git_status");
assert!(handback.get("commits").is_none(), "{handback}");
}
struct WriteThenGrind {
sequence: AtomicUsize,
requests: Arc<Mutex<Vec<serde_json::Value>>>,
}
impl Respond for WriteThenGrind {
fn respond(&self, request: &Request) -> ResponseTemplate {
let body: serde_json::Value = serde_json::from_slice(&request.body).expect("chat body");
self.requests.lock().expect("capture").push(body);
let n = self.sequence.fetch_add(1, Ordering::SeqCst);
let (name, arguments) = if n == 0 {
("write_file", "{\"path\":\"out.txt\",\"content\":\"x\\n\"}")
} else {
("list_dir", "{\"path\":\".\"}")
};
if request.url.path() == "/v1/responses" {
return ResponseTemplate::new(200).set_body_json(serde_json::json!({
"id": format!("resp_{n}"), "status": "completed", "model": "m",
"output": [{"type": "function_call", "id": format!("fc_{n}"),
"call_id": format!("c{n}"), "name": name, "arguments": arguments,
"status": "completed"}]
}));
}
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": "m",
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{"id": format!("c{n}"), "type": "function",
"function": {"name": name, "arguments": arguments}}]
},
"finish_reason": "tool_calls"
}]
}))
}
}
async fn assert_write_then_no_progress_stops(api: &str) {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(WriteThenGrind {
sequence: AtomicUsize::new(0),
requests: requests.clone(),
})
.mount(&server)
.await;
Mock::given(method("POST"))
.and(path("/v1/responses"))
.respond_with(WriteThenGrind {
sequence: AtomicUsize::new(0),
requests: requests.clone(),
})
.mount(&server)
.await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("workspace");
let config_path = control.path().join("cfg.toml");
std::fs::write(
&config_path,
format!(
"default_backend = \"b\"\n\n[[backends]]\nname = \"b\"\nendpoint = \"{}\"\nmodel = \"m\"\nkind = \"openai\"\n\n[initiative.no_progress]\nsteer_after = 2\nstop_after = 3\n",
server.uri()
),
)
.expect("config");
let instruction = control.path().join("task.md");
std::fs::write(&instruction, "Write out.txt, then stop.\n").expect("instruction");
let events_path = control.path().join("events.jsonl");
common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["--backend-api", api])
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "40"])
.assert()
.success();
let lines: Vec<serde_json::Value> = std::fs::read_to_string(&events_path)
.expect("events")
.lines()
.map(|l| serde_json::from_str(l).expect("json line"))
.collect();
let result = lines
.iter()
.find(|r| r["kind"] == "solve_result")
.expect("solve_result");
assert_eq!(result["end_reason"], "Some(NoProgress)", "{result}");
assert_eq!(result["status"], "incomplete");
assert!(
result["reply_chars"].as_u64().unwrap() > 0,
"harness notice: {result}"
);
let contract = lines
.iter()
.find(|r| r.get("contract_version").is_some())
.expect("contract");
assert_eq!(contract["outcome"], "timeout");
let requests = requests.lock().expect("capture");
assert_eq!(
requests.len(),
5,
"write, new directory evidence, then three grinding rounds; no summary call"
);
assert!(
requests.iter().all(|r| r.get("tools").is_some()),
"no tools-disabled summary"
);
let last_messages = requests[4]
.get("messages")
.or_else(|| requests[4].get("input"))
.expect("messages or input")
.to_string();
assert!(
last_messages.contains("rounds produced no new evidence"),
"the steer must precede the final round: {last_messages}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn a_write_then_no_progress_is_steered_then_stopped_like_a_cap() {
assert_write_then_no_progress_stops("chat").await;
}
#[tokio::test(flavor = "multi_thread")]
async fn a_write_then_no_progress_is_stopped_on_the_responses_wire_too() {
assert_write_then_no_progress_stops("responses").await;
}
struct WriteThenIdless {
sequence: AtomicUsize,
requests: Arc<Mutex<Vec<serde_json::Value>>>,
}
impl Respond for WriteThenIdless {
fn respond(&self, request: &Request) -> ResponseTemplate {
let body: serde_json::Value = serde_json::from_slice(&request.body).expect("chat body");
self.requests.lock().expect("capture").push(body);
let n = self.sequence.fetch_add(1, Ordering::SeqCst);
let call = if n == 0 {
serde_json::json!({"id": "c0", "type": "function", "function": {
"name": "write_file", "arguments": "{\"path\":\"out.txt\",\"content\":\"x\\n\"}"}})
} else {
serde_json::json!({"type": "function", "function": {
"name": "list_dir", "arguments": "{\"path\":\".\"}"}})
};
ResponseTemplate::new(200).set_body_json(serde_json::json!({
"model": "m",
"choices": [{"message": {"role": "assistant", "content": null, "tool_calls": [call]},
"finish_reason": "tool_calls"}]
}))
}
}
#[tokio::test(flavor = "multi_thread")]
async fn an_idless_reask_round_is_counted_by_the_brake_and_does_not_reset_it() {
let server = MockServer::start().await;
let requests = Arc::new(Mutex::new(Vec::new()));
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(WriteThenIdless {
sequence: AtomicUsize::new(0),
requests: requests.clone(),
})
.mount(&server)
.await;
let control = tempfile::tempdir().expect("control dir");
let workspace = tempfile::tempdir().expect("workspace");
let config_path = control.path().join("cfg.toml");
std::fs::write(
&config_path,
format!(
"default_backend = \"b\"\n\n[[backends]]\nname = \"b\"\nendpoint = \"{}\"\nmodel = \"m\"\nkind = \"openai\"\n\n[initiative.no_progress]\nsteer_after = 0\nstop_after = 2\n",
server.uri()
),
)
.expect("config");
let instruction = control.path().join("task.md");
std::fs::write(&instruction, "Write out.txt, then stop.\n").expect("instruction");
let events_path = control.path().join("events.jsonl");
common::newt()
.env_remove("NEWT_TEAM")
.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(workspace.path())
.arg("--instruction-file")
.arg(&instruction)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "40"])
.assert()
.success();
let result = solve_result_from(&events_path);
assert_eq!(result["end_reason"], "Some(NoProgress)", "{result}");
assert_eq!(result["status"], "incomplete");
assert!(
result["error"].is_null(),
"not the correlation abort: {result}"
);
assert_eq!(
requests.lock().expect("capture").len(),
3,
"the write, then two re-asked rounds; the stop precedes a third"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn a_signed_ocap_fs_read_grant_is_admitted_into_headless_caveats_and_the_contract() {
const CLAIM: &str = "FINAL-CLAIM-2524-ocap-grant";
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"choices": [{"message": {"role": "assistant", "content": CLAIM}, "finish_reason": "stop"}]
})))
.mount(&server)
.await;
let mut cmd = common::newt();
let home = cmd.home().to_path_buf();
let config_dir = cmd.config_dir();
let key = newt_identity::UserKey::generate();
let identity_path = config_dir.join("identity.pem");
key.save(&identity_path).expect("save disposable root key");
let ocap_dir = config_dir.join("ocap");
std::fs::create_dir_all(&ocap_dir).expect("ocap dir");
let granted_path = home.join("outside-canvas-token");
std::fs::write(&granted_path, "token\n").expect("write outside file");
let mut file = newt_core::ocap_store::PolicyFile::parse(&format!(
"[[fs]]\npath = '{}'\n",
granted_path.display()
))
.expect("parse approve.toml");
let (signed, refused) = newt_core::ocap_store::sign_approves(
&mut file,
|_, _| false,
|payload| key.sign(payload).to_bytes(),
);
assert_eq!(signed, 1);
assert!(refused.is_empty());
std::fs::write(
ocap_dir.join("approve.toml"),
file.to_toml().expect("serialize approve.toml"),
)
.expect("write approve.toml");
let workspace = home.join("workspace");
std::fs::create_dir(&workspace).unwrap();
let config_path = home.join("config.toml");
std::fs::write(
&config_path,
format!(
"default_backend = \"b\"\n\n[[backends]]\nname = \"b\"\nendpoint = \"{}\"\nmodel = \"m\"\nkind = \"openai\"\n",
server.uri()
),
)
.expect("write config");
let instruction = home.join("task.md");
std::fs::write(&instruction, "Finish without calling a tool.\n").expect("instruction");
let events_path = home.join("events.jsonl");
cmd.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(&workspace)
.arg("--instruction-file")
.arg(&instruction)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
let contract = contract_from(&events_path);
let durable_grants = contract["effective_config"]["durable_grants"]
.as_array()
.expect("durable_grants stanza present when a grant was admitted");
assert_eq!(
durable_grants,
&vec![serde_json::json!(format!(
"fs_read:{} (no-op: already permitted)",
granted_path.display()
))],
"{contract}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn headless_reading_the_ocap_store_never_mints_an_identity_key() {
const CLAIM: &str = "FINAL-CLAIM-2532-no-mint";
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/chat/completions"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"choices": [{"message": {"role": "assistant", "content": CLAIM}, "finish_reason": "stop"}]
})))
.mount(&server)
.await;
let mut cmd = common::newt();
let home = cmd.home().to_path_buf();
let config_dir = cmd.config_dir();
let identity_path = config_dir.join("identity.pem");
assert!(!identity_path.exists(), "no key before the run");
let workspace = home.join("workspace");
std::fs::create_dir(&workspace).unwrap();
let config_path = home.join("config.toml");
std::fs::write(
&config_path,
format!(
"default_backend = \"b\"\n\n[[backends]]\nname = \"b\"\nendpoint = \"{}\"\nmodel = \"m\"\nkind = \"openai\"\n",
server.uri()
),
)
.expect("write config");
let instruction = home.join("task.md");
std::fs::write(&instruction, "Finish without calling a tool.\n").expect("instruction");
let events_path = home.join("events.jsonl");
cmd.arg("--config")
.arg(&config_path)
.args(["headless", "--cwd"])
.arg(&workspace)
.arg("--instruction-file")
.arg(&instruction)
.arg("--events")
.arg(&events_path)
.args(["--max-rounds", "1"])
.assert()
.success();
assert!(
!identity_path.exists(),
"reading the OCAP store must never mint identity.pem"
);
let contract = contract_from(&events_path);
assert!(
contract["effective_config"]["durable_grants"].is_null(),
"no key on disk means no approves, not a freshly-minted empty store: {contract}"
);
}