use car_memgine::{MemgineEngine, SkillOutcome, SkillTrigger};
use car_server_core::{run_dispatch, ServerState, ServerStateConfig};
use chrono::Utc;
use futures::{SinkExt, StreamExt};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;
use tempfile::TempDir;
use tokio::net::TcpListener;
use tokio::sync::Mutex;
use tokio_tungstenite::tungstenite::Message;
use tokio_tungstenite::{accept_async, connect_async, MaybeTlsStream, WebSocketStream};
fn state_with_engine(journal_dir: std::path::PathBuf, engine: MemgineEngine) -> Arc<ServerState> {
let approvals = journal_dir.join("approvals.jsonl");
let cfg = ServerStateConfig::new(journal_dir)
.with_shared_memgine(Arc::new(Mutex::new(engine)))
.with_approval_journal(approvals);
Arc::new(ServerState::with_config(cfg))
}
fn pressured_engine() -> MemgineEngine {
let mut e = MemgineEngine::new(None);
for i in 0..25 {
e.ingest_fact(
&format!("f{i}"),
&format!("k{i}"),
&format!("value {i}"),
"test",
"user",
Utc::now(),
"global",
None,
vec![],
false,
);
}
for i in 0..8 {
e.report_fact_outdated(&format!("f{i}"));
}
for name in ["good", "bad"] {
e.ingest_skill(
name,
"",
"shell",
SkillTrigger::default(),
"s",
None,
vec![],
vec![],
);
}
for _ in 0..4 {
e.report_outcome("bad", SkillOutcome::Fail);
}
for _ in 0..10 {
e.report_outcome("good", SkillOutcome::Success);
}
for i in 0..12 {
e.ingest_conversation("user", &format!("turn {i}: context signal"), Utc::now());
}
e
}
async fn connect(
state: &Arc<ServerState>,
) -> WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>> {
let listener = TcpListener::bind(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
0,
)))
.await
.expect("bind loopback");
let addr = listener.local_addr().expect("local_addr");
let st = state.clone();
tokio::spawn(async move {
let (stream, peer) = listener.accept().await.expect("accept");
let ws = accept_async(stream).await.expect("ws handshake");
let (write, read) = ws.split();
let _ = run_dispatch(read, Box::pin(write), peer.to_string(), st).await;
});
let url = format!("ws://{}", addr);
let (ws, _resp) = connect_async(&url).await.expect("ws client connect");
ws
}
async fn send_recv(
ws: &mut WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>,
request: serde_json::Value,
) -> serde_json::Value {
let body = serde_json::to_string(&request).expect("request to_string");
ws.send(Message::Text(body.into())).await.expect("send");
let resp = ws.next().await.expect("frame").expect("frame ok");
let text = match resp {
Message::Text(t) => t.to_string(),
other => panic!("expected Text frame, got {:?}", other),
};
serde_json::from_str(&text).expect("parse response JSON")
}
fn decision_components(plan: &serde_json::Value) -> Vec<String> {
plan["decisions"]
.as_array()
.expect("decisions")
.iter()
.map(|d| d["component"].as_str().unwrap().to_string())
.collect()
}
#[tokio::test]
async fn evolution_plan_populates_live_components_and_omits_absent_sources() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), pressured_engine());
let mut ws = connect(&state).await;
let resp = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "p1", "method": "evolution.plan", "params": {}
}),
)
.await;
let plan = resp.get("result").expect("result");
let components = decision_components(plan);
for c in ["memory", "skills", "context"] {
assert!(components.contains(&c.to_string()), "{c} in {components:?}");
}
assert!(
!components.contains(&"harness".to_string()),
"harness must be absent on an empty session log: {components:?}"
);
let evolve_now: Vec<&str> = plan["evolve_now"]
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap())
.collect();
assert!(evolve_now.contains(&"memory"), "{evolve_now:?}");
assert!(evolve_now.contains(&"skills"), "{evolve_now:?}");
}
#[tokio::test]
async fn evolution_run_dry_run_reports_without_side_effects() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), pressured_engine());
let mut ws = connect(&state).await;
let resp = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "r1", "method": "evolution.run",
"params": { "dry_run": true }
}),
)
.await;
let result = resp.get("result").expect("result");
let steps = result["steps"].as_array().expect("steps");
let memory = steps
.iter()
.find(|s| s["component"] == "memory")
.expect("memory step");
assert_eq!(memory["ran"], true);
let outcome = memory["outcome"].as_str().unwrap();
assert!(
outcome.starts_with("dry_run: would consolidate"),
"{outcome}"
);
assert!(outcome.contains("maintenance:"), "{outcome}");
let skills = steps
.iter()
.find(|s| s["component"] == "skills")
.expect("skills step");
assert_eq!(skills["ran"], false);
assert_eq!(skills["outcome"], "no inference engine");
let events = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "q1", "method": "events.query",
"params": { "kinds": ["evolution_triggered"] }
}),
)
.await;
assert_eq!(events["result"]["count"], 0, "{events}");
}
#[tokio::test]
async fn evolution_run_real_memory_consolidates_and_audits() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), pressured_engine());
let mut ws = connect(&state).await;
let resp = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "r2", "method": "evolution.run", "params": {}
}),
)
.await;
let result = resp.get("result").expect("result");
let steps = result["steps"].as_array().expect("steps");
let memory = steps
.iter()
.find(|s| s["component"] == "memory")
.expect("memory step");
assert_eq!(memory["ran"], true);
let outcome = memory["outcome"].as_str().unwrap();
assert!(
outcome.contains("\"mechanism\":\"consolidate\""),
"{outcome}"
);
assert!(outcome.contains("\"maintenance\""), "{outcome}");
let evolved: Vec<&str> = result["evolved"]
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap())
.collect();
assert!(evolved.contains(&"memory"), "{evolved:?}");
let events = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "q2", "method": "events.query",
"params": { "kinds": ["evolution_triggered"] }
}),
)
.await;
assert_eq!(events["result"]["count"], 1, "{events}");
let ev = &events["result"]["events"][0];
assert_eq!(ev["data"]["source"], "evolution.run");
}
fn harness_baseline() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4
},
"recovery": { "retries": 12 },
"task_pass_rate": 0.5,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
async fn run_evolution(
ws: &mut WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>,
id: &str,
) -> serde_json::Value {
send_recv(
ws,
serde_json::json!({
"jsonrpc": "2.0", "id": id, "method": "evolution.run",
"params": { "harness_baseline_metrics": harness_baseline() }
}),
)
.await
}
fn harness_step(result: &serde_json::Value) -> serde_json::Value {
result["steps"]
.as_array()
.expect("steps")
.iter()
.find(|s| s["component"] == "harness")
.expect("harness step")
.clone()
}
#[tokio::test]
async fn approval_on_one_connection_applies_on_another() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let mut runner = connect(&state).await;
let r1 = run_evolution(&mut runner, "e1").await;
let result1 = r1.get("result").expect("result: {r1}");
let step1 = harness_step(result1);
assert_eq!(step1["ran"], true);
assert_eq!(step1["applied"], false, "{step1}");
assert!(
!result1["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "harness"),
"pending-only run must not claim harness evolved (S2): {result1}"
);
let pending = result1["pending_approvals"]
.as_array()
.expect("pending_approvals surfaced");
let fingerprint = pending[0]["fingerprint"].as_str().unwrap().to_string();
assert!(fingerprint.starts_with("harness:retry:"), "{fingerprint}");
let mut approver = connect(&state).await;
let a = send_recv(
&mut approver,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap1", "method": "permission.approve",
"params": { "fingerprint": fingerprint, "reason": "reviewed retry tuning" }
}),
)
.await;
assert!(a.get("result").is_some(), "approve failed: {a}");
let mut runner2 = connect(&state).await;
let r2 = run_evolution(&mut runner2, "e2").await;
let result2 = r2.get("result").expect("result");
let step2 = harness_step(result2);
assert_eq!(step2["ran"], true);
assert_eq!(step2["applied"], true, "{step2}");
assert!(
result2["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "harness"),
"{result2}"
);
let outcome2 = step2["outcome"].as_str().unwrap();
assert!(outcome2.contains("\"applied\":1"), "{outcome2}");
assert!(outcome2.contains("human_approved"), "{outcome2}");
}
#[tokio::test]
async fn dry_run_lists_pending_approvals_without_side_effects() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let mut ws = connect(&state).await;
let r = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "d1", "method": "evolution.run",
"params": { "dry_run": true, "harness_baseline_metrics": harness_baseline() }
}),
)
.await;
let result = r.get("result").expect("result");
let pending = result["pending_approvals"]
.as_array()
.expect("dry_run must still list what needs approval");
assert!(!pending.is_empty());
assert!(
pending[0]["reason"]
.as_str()
.unwrap_or("")
.contains("harness_candidate_metrics"),
"the no-candidate-metrics reason is stated: {pending:?}"
);
let events = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "q", "method": "events.query",
"params": { "kinds": ["evolution_triggered"] }
}),
)
.await;
assert_eq!(
events["result"]["count"], 0,
"dry_run appends no audit event"
);
}
#[tokio::test]
async fn approval_survives_daemon_restart() {
let tmp = TempDir::new().unwrap();
let fingerprint = {
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let mut ws = connect(&state).await;
let r = run_evolution(&mut ws, "e1").await;
let fp = r["result"]["pending_approvals"][0]["fingerprint"]
.as_str()
.unwrap()
.to_string();
let a = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap", "method": "permission.approve",
"params": { "fingerprint": fp, "reason": "ok" }
}),
)
.await;
assert!(a.get("result").is_some(), "{a}");
fp
};
let state2 = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let mut ws2 = connect(&state2).await;
let r2 = run_evolution(&mut ws2, "e2").await;
let result2 = r2.get("result").expect("result");
let step2 = harness_step(result2);
assert_eq!(step2["applied"], true, "{step2}");
assert!(
result2.get("pending_approvals").is_none()
|| !result2["pending_approvals"]
.as_array()
.unwrap()
.iter()
.any(|p| p["fingerprint"] == fingerprint.as_str()),
"an approved fingerprint must not re-surface as pending: {result2}"
);
}
struct StubMeasurer {
baseline: Result<car_eventlog::harness_metrics::HarnessMetrics, String>,
candidate: Result<car_eventlog::harness_metrics::HarnessMetrics, String>,
configs: std::sync::Mutex<Vec<Option<car_memgine::HarnessConfig>>>,
}
impl StubMeasurer {
fn new(
baseline: serde_json::Value,
candidate: Result<serde_json::Value, String>,
) -> Arc<StubMeasurer> {
Arc::new(StubMeasurer {
baseline: Ok(serde_json::from_value(baseline).expect("baseline HarnessMetrics")),
candidate: candidate.map(|v| serde_json::from_value(v).expect("candidate metrics")),
configs: std::sync::Mutex::new(Vec::new()),
})
}
fn failing_baseline(error: &str) -> Arc<StubMeasurer> {
Arc::new(StubMeasurer {
baseline: Err(error.to_string()),
candidate: Err(error.to_string()),
configs: std::sync::Mutex::new(Vec::new()),
})
}
fn calls(&self) -> Vec<Option<car_memgine::HarnessConfig>> {
self.configs.lock().unwrap().clone()
}
}
#[async_trait::async_trait]
impl car_server_core::evolution::HarnessMeasurer for StubMeasurer {
async fn measure(
&self,
_request: &car_server_core::evolution::HarnessMeasureRequest,
harness_config: Option<&car_memgine::HarnessConfig>,
memgine_config: Option<&car_memgine::MemgineConfig>,
) -> Result<car_eventlog::harness_metrics::HarnessMetrics, String> {
assert!(
memgine_config.is_none(),
"the harness arm must never vary the context config: a replay that \
varies two configs at once produces a verdict that attributes to neither"
);
let n = {
let mut calls = self.configs.lock().unwrap();
calls.push(harness_config.cloned());
calls.len()
};
if n == 1 {
self.baseline.clone()
} else {
self.candidate.clone()
}
}
}
fn improved_candidate() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4
},
"recovery": { "retries": 3 },
"task_pass_rate": 0.75,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
fn regressed_candidate() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.1
},
"recovery": { "retries": 3 },
"task_pass_rate": 0.5,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
fn incomparable_candidate() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4
},
"recovery": { "retries": 3 },
"task_pass_rate": 1.0,
"task_pass_denominator": 8,
"tasks_unrunnable": 4
})
}
async fn run_with_measure(
ws: &mut WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>,
id: &str,
extra: serde_json::Value,
) -> serde_json::Value {
let mut params = serde_json::json!({
"harness_measure": { "model": "stub-model", "split": "held-out", "split_seed": 0 }
});
let obj = params.as_object_mut().unwrap();
for (k, v) in extra.as_object().expect("extra params object") {
obj.insert(k.clone(), v.clone());
}
send_recv(
ws,
serde_json::json!({
"jsonrpc": "2.0", "id": id, "method": "evolution.run", "params": params
}),
)
.await
}
fn harness_outcome(result: &serde_json::Value) -> serde_json::Value {
let step = harness_step(result);
let outcome = step["outcome"].as_str().expect("harness outcome string");
serde_json::from_str(outcome).expect("harness outcome is JSON")
}
fn detail_for(outcome: &serde_json::Value, component: &str) -> serde_json::Value {
outcome["details"]
.as_array()
.expect("details")
.iter()
.find(|d| d["component"] == component)
.unwrap_or_else(|| panic!("no detail for {component} in {outcome}"))
.clone()
}
#[tokio::test]
async fn daemon_measured_candidate_promotes_without_supplied_metrics() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let stub = StubMeasurer::new(harness_baseline(), Ok(improved_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m1", serde_json::json!({})).await;
let result = r.get("result").unwrap_or_else(|| panic!("result: {r}"));
let step = harness_step(result);
assert_eq!(step["applied"], true, "{step}");
assert!(
result["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "harness"),
"{result}"
);
let outcome = harness_outcome(result);
let retry = detail_for(&outcome, "retry_config");
assert_eq!(retry["status"], "applied", "{retry}");
assert_eq!(retry["governance"], "promoted", "{retry}");
assert_eq!(outcome["measurement"]["status"], "measured", "{outcome}");
assert_eq!(outcome["measurement"]["split"], "held-out");
assert_eq!(outcome["measurement"]["model"], "stub-model");
assert_eq!(
outcome["measurement"]["baseline_metrics"]["recovery"]["retries"],
12
);
assert_eq!(retry["candidate_metrics"]["recovery"]["retries"], 3);
}
#[tokio::test]
async fn daemon_measured_regression_is_rejected_by_the_gate() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
state.set_harness_measurer(StubMeasurer::new(
harness_baseline(),
Ok(regressed_candidate()),
));
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m2", serde_json::json!({})).await;
let result = r.get("result").expect("result");
let step = harness_step(result);
assert_eq!(step["applied"], false, "{step}");
assert!(
!result["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "harness"),
"a rejected candidate must not report the harness as evolved: {result}"
);
let retry = detail_for(&harness_outcome(result), "retry_config");
assert_eq!(retry["status"], "rejected_by_gate", "{retry}");
}
#[tokio::test]
async fn a_failed_candidate_measurement_fabricates_nothing() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
state.set_harness_measurer(StubMeasurer::new(
harness_baseline(),
Err("model backend unreachable".into()),
));
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m3", serde_json::json!({})).await;
let result = r.get("result").expect("result");
assert_eq!(harness_step(result)["applied"], false);
let outcome = harness_outcome(result);
let retry = detail_for(&outcome, "retry_config");
assert_eq!(retry["status"], "measurement_failed", "{retry}");
assert!(
retry["error"]
.as_str()
.unwrap_or_default()
.contains("model backend unreachable"),
"{retry}"
);
assert!(
retry.get("candidate_metrics").is_none(),
"a failed measurement must carry NO metrics: {retry}"
);
assert_eq!(harness_step(result)["ran"], true);
}
async fn seed_recurring_action_failures(
ws: &mut WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>,
) {
for i in 0..10 {
let r = send_recv(
ws,
serde_json::json!({
"jsonrpc": "2.0", "id": format!("seed{i}"), "method": "proposal.submit",
"params": { "proposal": {
"source": "test",
"actions": [{
"id": "a1",
"type": "assertion",
"parameters": { "key": "never_set", "expected": "something" }
}]
}}
}),
)
.await;
let results = r["result"]["results"]
.as_array()
.unwrap_or_else(|| panic!("submit {i} returned no results: {r}"));
assert_eq!(
results[0]["status"], "failed",
"the seed action must FAIL (not be rejected) — a rejection would \
feed verification_strength instead of the failure signal: {r}"
);
}
}
#[tokio::test]
async fn dry_run_measures_nothing_and_says_so() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let stub = StubMeasurer::new(harness_baseline(), Ok(improved_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
seed_recurring_action_failures(&mut ws).await;
let r = run_with_measure(
&mut ws,
"m4",
serde_json::json!({ "dry_run": true, "policy": { "pressure_threshold": 0.05 } }),
)
.await;
let result = r.get("result").expect("result");
assert!(
stub.calls().is_empty(),
"dry_run must not spend a single measurement: {:?}",
stub.calls()
);
let outcome = harness_outcome(result);
assert_eq!(
outcome["measurement"]["status"], "skipped_dry_run",
"{outcome}"
);
let pending = result["pending_approvals"]
.as_array()
.expect("dry_run still lists what needs approval");
assert!(pending
.iter()
.all(|p| p["reason"].as_str().unwrap_or_default().contains("dry_run")));
assert_eq!(outcome["applied"], 0, "{outcome}");
}
#[tokio::test]
async fn harness_measure_and_supplied_metrics_are_mutually_exclusive() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
state.set_harness_measurer(StubMeasurer::new(
harness_baseline(),
Ok(improved_candidate()),
));
let mut ws = connect(&state).await;
let r = run_with_measure(
&mut ws,
"m5",
serde_json::json!({ "harness_candidate_metrics": improved_candidate() }),
)
.await;
let err = r
.get("error")
.unwrap_or_else(|| panic!("expected error: {r}"));
let msg = err["message"].as_str().unwrap_or_default();
assert!(msg.contains("harness_measure"), "{msg}");
assert!(msg.contains("harness_candidate_metrics"), "{msg}");
}
#[tokio::test]
async fn harness_measure_without_an_installed_measurer_errs() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m6", serde_json::json!({})).await;
let err = r
.get("error")
.unwrap_or_else(|| panic!("expected error: {r}"));
let msg = err["message"].as_str().unwrap_or_default();
assert!(
msg.contains("no in-process harness evaluator"),
"the error must say the build has no evaluator: {msg}"
);
}
#[tokio::test]
async fn the_measurer_receives_the_candidate_config_not_the_baseline_twice() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let stub = StubMeasurer::new(harness_baseline(), Ok(improved_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m7", serde_json::json!({})).await;
assert!(r.get("result").is_some(), "{r}");
let calls = stub.calls();
assert_eq!(
calls.len(),
2,
"one baseline replay plus one candidate replay — the patchless \
safety-affecting mutation is never measured: {calls:?}"
);
assert_eq!(
calls[0], None,
"the baseline runs under the session's live config, which is the \
runtime default on a fresh session: {calls:?}"
);
assert_eq!(
calls[1],
Some(car_memgine::HarnessConfig {
max_retries: 2,
retry_backoff_ms: 100,
..Default::default()
}),
"the candidate must be measured under the PATCHED config: {calls:?}"
);
let outcome = harness_outcome(r.get("result").unwrap());
let validator = detail_for(&outcome, "validator");
assert_eq!(validator["status"], "pending_approval", "{validator}");
assert!(
validator.get("candidate_metrics").is_none(),
"an unmeasured mutation must carry no metrics: {validator}"
);
}
fn healthy_baseline() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 20,
"failed_attempts": 0,
"success_rate": 1.0
},
"recovery": { "retries": 0 },
"task_pass_rate": 1.0,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
#[tokio::test]
async fn the_measurement_is_reported_even_when_harness_is_not_elected() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
let stub = StubMeasurer::new(healthy_baseline(), Ok(improved_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m8", serde_json::json!({})).await;
let result = r.get("result").unwrap_or_else(|| panic!("result: {r}"));
assert!(
result["steps"]
.as_array()
.expect("steps")
.iter()
.all(|s| s["component"] != "harness"),
"a zero-pressure harness must be skipped, not dispatched: {result}"
);
assert_eq!(
stub.calls().len(),
1,
"the baseline replay runs before the plan: {:?}",
stub.calls()
);
let measurement = &result["measurement"];
assert_eq!(measurement["status"], "measured", "{result}");
assert_eq!(measurement["split"], "held-out", "{measurement}");
assert_eq!(measurement["model"], "stub-model", "{measurement}");
assert_eq!(
measurement["baseline_metrics"]["trajectory_efficiency"]["attempts_total"], 20,
"the full baseline document is what makes the replay re-derivable: {measurement}"
);
}
#[tokio::test]
async fn a_failed_baseline_measurement_is_never_silently_swallowed() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
state.set_harness_measurer(StubMeasurer::failing_baseline("bench backend unreachable"));
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m9", serde_json::json!({})).await;
let result = r.get("result").unwrap_or_else(|| panic!("result: {r}"));
assert!(
result["steps"]
.as_array()
.expect("steps")
.iter()
.all(|s| s["component"] != "harness"),
"premise: a failed baseline elects no harness component on a fresh \
session, so the step cannot carry the error: {result}"
);
let measurement = &result["measurement"];
assert_eq!(measurement["status"], "measurement_failed", "{result}");
assert!(
measurement["error"]
.as_str()
.unwrap_or_default()
.contains("bench backend unreachable"),
"the failure must name what went wrong: {measurement}"
);
assert!(
measurement.get("baseline_metrics").is_none(),
"a failed measurement must carry NO metrics: {measurement}"
);
assert!(
result["evolved"]
.as_array()
.expect("evolved")
.iter()
.all(|v| v != "harness"),
"{result}"
);
}
#[tokio::test]
async fn a_shrunken_task_denominator_is_incomparable_and_applies_nothing() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
state.set_harness_measurer(StubMeasurer::new(
harness_baseline(),
Ok(incomparable_candidate()),
));
let mut ws = connect(&state).await;
let r = run_with_measure(&mut ws, "m10", serde_json::json!({})).await;
let result = r.get("result").unwrap_or_else(|| panic!("result: {r}"));
let step = harness_step(result);
assert_eq!(step["applied"], false, "{step}");
assert!(
result["evolved"]
.as_array()
.expect("evolved")
.iter()
.all(|v| v != "harness"),
"an undecidable comparison must not report the harness as evolved: {result}"
);
let outcome = harness_outcome(result);
let retry = detail_for(&outcome, "retry_config");
assert_eq!(
retry["status"], "incomparable",
"not `rejected_by_gate` — nothing says the candidate is bad, only that \
this evidence cannot decide it: {retry}"
);
let reason = retry["reason"].as_str().unwrap_or_default();
assert!(
reason.contains("12") && reason.contains("8"),
"the reason must name both denominators: {retry}"
);
assert!(
retry.get("rollback_patch").is_none(),
"nothing was applied, so there is nothing to roll back: {retry}"
);
assert_eq!(outcome["applied"], 0, "{outcome}");
assert_eq!(retry["candidate_metrics"]["task_pass_denominator"], 8);
assert_eq!(outcome["measurement"]["status"], "measured", "{outcome}");
}
fn saturated_engine_with(batch_size: usize) -> MemgineEngine {
let cfg = car_memgine::MemgineConfig {
token_budget: 400, compaction_batch_size: batch_size,
speculative_compaction_interval: 0,
..Default::default()
};
let mut e = MemgineEngine::new(Some(cfg));
let base = Utc::now();
for i in 0..12i64 {
e.ingest_conversation(
"user",
&format!("turn {i}: {}", "x".repeat(220)),
base + chrono::Duration::seconds(i),
);
}
e
}
fn saturated_engine() -> MemgineEngine {
saturated_engine_with(8)
}
fn step_for(result: &serde_json::Value, component: &str) -> serde_json::Value {
result["steps"]
.as_array()
.expect("steps")
.iter()
.find(|s| s["component"] == component)
.unwrap_or_else(|| panic!("no {component} step in {result}"))
.clone()
}
fn context_outcome(result: &serde_json::Value) -> serde_json::Value {
let step = step_for(result, "context");
let outcome = step["outcome"].as_str().expect("context outcome string");
serde_json::from_str(outcome).expect("context outcome is JSON")
}
fn context_detail(result: &serde_json::Value) -> serde_json::Value {
detail_for(&context_outcome(result), "context_budget")
}
async fn run_context_cycle(
ws: &mut WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>,
id: &str,
dry_run: bool,
) -> serde_json::Value {
let resp = send_recv(
ws,
serde_json::json!({
"jsonrpc": "2.0", "id": id, "method": "evolution.run",
"params": { "dry_run": dry_run }
}),
)
.await;
resp.get("result")
.unwrap_or_else(|| panic!("evolution.run failed: {resp}"))
.clone()
}
async fn keep_recent(state: &Arc<ServerState>) -> usize {
state
.shared_memgine
.as_ref()
.expect("shared engine")
.lock()
.await
.context_evolution_signals()
.expect("live context signal")
.conversation_keep_recent
}
async fn conversation_tokens(state: &Arc<ServerState>) -> usize {
state
.shared_memgine
.as_ref()
.expect("shared engine")
.lock()
.await
.context_evolution_signals()
.expect("live context signal")
.conversation_tokens
}
#[tokio::test]
async fn context_is_no_longer_reported_as_not_executable() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let mut ws = connect(&state).await;
let result = run_context_cycle(&mut ws, "c1", false).await;
let step = step_for(&result, "context");
assert_eq!(step["ran"], true, "{step}");
assert_eq!(
step["out_of_scope"], false,
"context is executed, not excused: {step}"
);
let outcome = context_outcome(&result);
assert_eq!(outcome["mechanism"], "context_evolution", "{outcome}");
assert_eq!(
outcome["mutations"], 1,
"the saturated layer must diagnose exactly one mutation: {outcome}"
);
let steps = serde_json::to_string(&result["steps"]).unwrap();
assert!(
!steps.contains("not_executable"),
"no step may report a scope decision as an execution failure: {steps}"
);
}
#[tokio::test]
async fn tools_is_recorded_as_out_of_scope_not_a_failure() {
let tmp = TempDir::new().unwrap();
let manifest = tmp.path().join("connectors.json");
std::fs::write(
&manifest,
r#"{"connectors":[{"slug":"unreachable","name":"Unreachable",
"url":"http://127.0.0.1:1/mcp","secret_headers":[],"enabled_tools":[]}]}"#,
)
.unwrap();
let state = state_with_engine(tmp.path().join("journals"), MemgineEngine::new(None));
state
.connectors
.set(Arc::new(car_connectors::ConnectorManager::with_path(
state.mcp_executor.clone(),
manifest,
)))
.unwrap_or_else(|_| panic!("connector manager was already initialized"));
let mut ws = connect(&state).await;
let result = run_context_cycle(&mut ws, "t1", false).await;
let step = step_for(&result, "tools");
assert_eq!(step["ran"], true, "a boundary is not a failure: {step}");
assert_eq!(step["applied"], false, "{step}");
assert_eq!(step["out_of_scope"], true, "{step}");
assert!(
!result["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "tools"),
"{result}"
);
assert!(
result["out_of_scope"]
.as_array()
.expect("out_of_scope list")
.iter()
.any(|v| v == "tools"),
"{result}"
);
let reason = step["outcome"].as_str().unwrap();
assert!(reason.contains("credentials"), "{reason}");
assert!(reason.contains("connectors.*"), "{reason}");
}
#[tokio::test]
async fn a_context_proposal_waits_for_approval_then_applies_on_another_connection() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let mut runner = connect(&state).await;
let r1 = run_context_cycle(&mut runner, "c1", false).await;
let d1 = context_detail(&r1);
assert_eq!(d1["status"], "pending_approval", "{d1}");
assert!(
!r1["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"a pending proposal has evolved nothing: {r1}"
);
assert_eq!(keep_recent(&state).await, original_keep);
let pending = r1["pending_approvals"]
.as_array()
.expect("pending_approvals surfaced");
let entry = pending
.iter()
.find(|p| {
p["fingerprint"]
.as_str()
.is_some_and(|f| f.starts_with("context:"))
})
.unwrap_or_else(|| panic!("no context fingerprint in {pending:?}"));
let fingerprint = entry["fingerprint"].as_str().unwrap().to_string();
assert!(!fingerprint.starts_with("harness:"), "{fingerprint}");
let reason = entry["reason"].as_str().unwrap();
assert!(reason.contains("context_measure"), "{reason}");
assert!(reason.contains("human gate"), "{reason}");
assert!(
!reason.contains("no memgine attached"),
"the old \"the bench cannot see context\" claim must not survive: {reason}"
);
let mut approver = connect(&state).await;
let a = send_recv(
&mut approver,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap1", "method": "permission.approve",
"params": { "fingerprint": fingerprint, "reason": "reviewed the keep-recent cut" }
}),
)
.await;
assert!(a.get("result").is_some(), "approve failed: {a}");
let tokens_before = conversation_tokens(&state).await;
let mut runner2 = connect(&state).await;
let r2 = run_context_cycle(&mut runner2, "c2", false).await;
let d2 = context_detail(&r2);
assert_eq!(d2["status"], "applied", "{d2}");
assert_eq!(d2["governance"], "human_approved", "{d2}");
assert_eq!(
d2["conversation_tokens_baseline"], tokens_before as u64,
"{d2}"
);
assert!(
d2["conversation_tokens_after"].as_u64().unwrap() < tokens_before as u64,
"an applied context change must have cut conversation tokens: {d2}"
);
assert_eq!(
d2["rollback_patch"]["conversation_keep_recent"], original_keep as u64,
"{d2}"
);
assert!(
r2["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"{r2}"
);
assert_eq!(keep_recent(&state).await, original_keep / 2);
assert_eq!(
conversation_tokens(&state).await,
d2["conversation_tokens_after"].as_u64().unwrap() as usize
);
}
#[tokio::test]
async fn a_context_change_that_does_not_cut_tokens_is_rolled_back() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine_with(1));
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let mut ws = connect(&state).await;
let r1 = run_context_cycle(&mut ws, "c1", false).await;
let fingerprint = r1["pending_approvals"]
.as_array()
.expect("pending_approvals")
.iter()
.find(|p| {
p["fingerprint"]
.as_str()
.is_some_and(|f| f.starts_with("context:"))
})
.expect("context fingerprint")["fingerprint"]
.as_str()
.unwrap()
.to_string();
let a = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap1", "method": "permission.approve",
"params": { "fingerprint": fingerprint, "reason": "approved" }
}),
)
.await;
assert!(a.get("result").is_some(), "approve failed: {a}");
let r2 = run_context_cycle(&mut ws, "c2", false).await;
let d = context_detail(&r2);
assert_eq!(d["status"], "rolled_back", "{d}");
assert_eq!(
d["conversation_tokens_after"], d["conversation_tokens_baseline"],
"the case under test is a change that saved nothing: {d}"
);
assert!(d.get("rollback_error").is_none(), "{d}");
assert!(
!r2["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"a rolled-back change evolved nothing: {r2}"
);
assert_eq!(context_outcome(&r2)["applied"], 0);
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
}
fn uncompacted_engine() -> MemgineEngine {
let cfg = car_memgine::MemgineConfig {
token_budget: 1600, compaction_batch_size: 8,
speculative_compaction_interval: 0,
conversation_keep_recent: 40,
..Default::default()
};
let mut e = MemgineEngine::new(Some(cfg));
let base = Utc::now();
for i in 0..40i64 {
e.ingest_conversation(
"user",
&format!("turn {i}: {}", "x".repeat(220)),
base + chrono::Duration::seconds(i),
);
}
e.apply_context_patch(&car_memgine::ContextConfigPatch {
conversation_keep_recent: Some(6),
})
.expect("lower keep_recent to the value under test");
e
}
#[tokio::test]
async fn a_context_change_is_measured_against_a_baseline_compaction_not_the_uncompacted_layer() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), uncompacted_engine());
let original_keep = keep_recent(&state).await;
let tokens_uncompacted = conversation_tokens(&state).await;
let mut ws = connect(&state).await;
let r1 = run_context_cycle(&mut ws, "c1", false).await;
let fingerprint = r1["pending_approvals"]
.as_array()
.expect("pending_approvals")
.iter()
.find(|p| {
p["fingerprint"]
.as_str()
.is_some_and(|f| f.starts_with("context:"))
})
.expect("context fingerprint")["fingerprint"]
.as_str()
.unwrap()
.to_string();
let a = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap1", "method": "permission.approve",
"params": { "fingerprint": fingerprint, "reason": "approved" }
}),
)
.await;
assert!(a.get("result").is_some(), "approve failed: {a}");
let r2 = run_context_cycle(&mut ws, "c2", false).await;
let d = context_detail(&r2);
let baseline = d["conversation_tokens_baseline"].as_u64().unwrap();
let after = d["conversation_tokens_after"].as_u64().unwrap();
assert!(
baseline < tokens_uncompacted as u64,
"baseline compaction under the unchanged knob must itself cut tokens \
({tokens_uncompacted} → {baseline}), else this fixture proves nothing: {d}"
);
assert!(d["baseline_turns_summarized"].as_u64().unwrap() > 0, "{d}");
assert_eq!(
after, baseline,
"the change is credited with none of the baseline's saving: {d}"
);
assert_eq!(
d["turns_summarized"], 0,
"the engine's own gate refused the second pass; that is the case under test: {d}"
);
assert!(
d["reason"].as_str().unwrap().contains("did no work at all"),
"the report must distinguish \"nothing to compact right now\" from \"this knob \
cannot help\": {d}"
);
assert_eq!(
d["status"], "rolled_back",
"a change that saved nothing over the baseline must be reverted, however \
much the baseline itself saved: {d}"
);
assert!(
!r2["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"{r2}"
);
assert_eq!(keep_recent(&state).await, original_keep);
}
#[tokio::test]
async fn a_falsified_context_mutation_is_backed_off_on_the_next_cadence_tick() {
use car_server_core::evolution::{run_context_evolution, ContextBackoff};
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine_with(1));
let engine = state.shared_memgine.as_ref().unwrap().clone();
let backoff = std::sync::Mutex::new(ContextBackoff::default());
let pending = std::sync::Mutex::new(Vec::new());
run_context_evolution(&engine, &state, false, &pending, Some((&backoff, 1)), None)
.await
.expect("tick 1");
let entry = pending.lock().unwrap().first().cloned().expect("pending");
let fingerprint = entry["fingerprint"].as_str().unwrap().to_string();
let mut ws = connect(&state).await;
let a = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap1", "method": "permission.approve",
"params": { "fingerprint": fingerprint, "reason": "approved" }
}),
)
.await;
assert!(a.get("result").is_some(), "approve failed: {a}");
let out = run_context_evolution(&engine, &state, false, &pending, Some((&backoff, 2)), None)
.await
.expect("tick 2");
let d2 = detail_for(
&serde_json::from_str::<serde_json::Value>(&out.summary).unwrap(),
"context_budget",
);
assert_eq!(d2["status"], "rolled_back", "{d2}");
assert!(
!out.applied,
"a rolled-back mutation evolved nothing: {out:?}"
);
let out3 = run_context_evolution(&engine, &state, false, &pending, Some((&backoff, 3)), None)
.await
.expect("tick 3");
let d3 = detail_for(
&serde_json::from_str::<serde_json::Value>(&out3.summary).unwrap(),
"context_budget",
);
assert_eq!(d3["status"], "in_backoff", "{d3}");
assert_eq!(
d3["governance"], "human_approved",
"the approval still stands: {d3}"
);
assert!(
d3.get("conversation_tokens_baseline").is_none(),
"no pass was run: {d3}"
);
let session = run_context_evolution(&engine, &state, false, &pending, None, None)
.await
.expect("session run");
let ds = detail_for(
&serde_json::from_str::<serde_json::Value>(&session.summary).unwrap(),
"context_budget",
);
assert_eq!(
ds["status"], "rolled_back",
"a person asking now gets the check now: {ds}"
);
}
#[tokio::test]
async fn dry_run_applies_no_context_change() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let mut ws = connect(&state).await;
let r1 = run_context_cycle(&mut ws, "c1", true).await;
let fingerprint = r1["pending_approvals"]
.as_array()
.expect("pending_approvals")
.iter()
.find(|p| {
p["fingerprint"]
.as_str()
.is_some_and(|f| f.starts_with("context:"))
})
.expect("context fingerprint")["fingerprint"]
.as_str()
.unwrap()
.to_string();
let a = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "ap1", "method": "permission.approve",
"params": { "fingerprint": fingerprint, "reason": "approved" }
}),
)
.await;
assert!(a.get("result").is_some(), "approve failed: {a}");
let r2 = run_context_cycle(&mut ws, "c2", true).await;
let d = context_detail(&r2);
assert_eq!(d["status"], "would_apply", "{d}");
assert_eq!(d["governance"], "human_approved", "{d}");
assert!(d.get("conversation_tokens_baseline").is_none(), "{d}");
assert!(
!r2["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"{r2}"
);
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
}
struct ContextStubMeasurer {
baseline: Result<car_eventlog::harness_metrics::HarnessMetrics, String>,
candidate: Result<car_eventlog::harness_metrics::HarnessMetrics, String>,
keep_recents: std::sync::Mutex<Vec<usize>>,
interloper: Option<(Arc<tokio::sync::Mutex<MemgineEngine>>, usize)>,
}
impl ContextStubMeasurer {
fn new(
baseline: serde_json::Value,
candidate: Result<serde_json::Value, String>,
) -> Arc<ContextStubMeasurer> {
Arc::new(ContextStubMeasurer {
baseline: Ok(serde_json::from_value(baseline).expect("baseline HarnessMetrics")),
candidate: candidate.map(|v| serde_json::from_value(v).expect("candidate metrics")),
keep_recents: std::sync::Mutex::new(Vec::new()),
interloper: None,
})
}
fn failing_baseline(error: &str) -> Arc<ContextStubMeasurer> {
Arc::new(ContextStubMeasurer {
baseline: Err(error.to_string()),
candidate: Err(error.to_string()),
keep_recents: std::sync::Mutex::new(Vec::new()),
interloper: None,
})
}
fn mutating_the_engine_between_replays(
baseline: serde_json::Value,
candidate: serde_json::Value,
engine: Arc<tokio::sync::Mutex<MemgineEngine>>,
new_keep_recent: usize,
) -> Arc<ContextStubMeasurer> {
Arc::new(ContextStubMeasurer {
baseline: Ok(serde_json::from_value(baseline).expect("baseline HarnessMetrics")),
candidate: Ok(serde_json::from_value(candidate).expect("candidate metrics")),
keep_recents: std::sync::Mutex::new(Vec::new()),
interloper: Some((engine, new_keep_recent)),
})
}
fn keep_recents(&self) -> Vec<usize> {
self.keep_recents.lock().unwrap().clone()
}
}
#[async_trait::async_trait]
impl car_server_core::evolution::HarnessMeasurer for ContextStubMeasurer {
async fn measure(
&self,
_request: &car_server_core::evolution::HarnessMeasureRequest,
harness_config: Option<&car_memgine::HarnessConfig>,
memgine_config: Option<&car_memgine::MemgineConfig>,
) -> Result<car_eventlog::harness_metrics::HarnessMetrics, String> {
assert!(
harness_config.is_none(),
"the context arm must not vary the harness config"
);
let cfg = memgine_config.expect("the context arm always installs a context config");
let n = {
let mut calls = self.keep_recents.lock().unwrap();
calls.push(cfg.conversation_keep_recent);
calls.len()
};
if n == 1 {
self.baseline.clone()
} else {
if let Some((engine, keep)) = &self.interloper {
engine
.lock()
.await
.apply_context_patch(&car_memgine::ContextConfigPatch {
conversation_keep_recent: Some(*keep),
})
.expect("the interloping config change must land");
}
self.candidate.clone()
}
}
}
fn context_baseline() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4,
"total_tokens": 100_000,
"model_calls": 40
},
"task_pass_rate": 0.5,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
fn improved_context_candidate() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4,
"total_tokens": 80_000,
"model_calls": 40
},
"task_pass_rate": 0.5,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
fn regressed_context_candidate() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4,
"total_tokens": 80_000,
"model_calls": 40
},
"task_pass_rate": 0.25,
"task_pass_denominator": 12,
"tasks_unrunnable": 0
})
}
fn incomparable_context_candidate() -> serde_json::Value {
serde_json::json!({
"trajectory_efficiency": {
"attempts_total": 20,
"actions_succeeded": 8,
"failed_attempts": 12,
"success_rate": 0.4,
"total_tokens": 80_000,
"model_calls": 40
},
"task_pass_rate": 1.0,
"task_pass_denominator": 8,
"tasks_unrunnable": 4
})
}
async fn run_context_measured(
ws: &mut WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>,
id: &str,
dry_run: bool,
) -> serde_json::Value {
let resp = send_recv(
ws,
serde_json::json!({
"jsonrpc": "2.0", "id": id, "method": "evolution.run",
"params": {
"dry_run": dry_run,
"context_measure": { "model": "stub-model", "split": "held-out", "split_seed": 0 }
}
}),
)
.await;
resp.get("result")
.unwrap_or_else(|| panic!("evolution.run failed: {resp}"))
.clone()
}
fn has_context_pending(result: &serde_json::Value) -> bool {
result["pending_approvals"]
.as_array()
.map(|a| {
a.iter().any(|p| {
p["fingerprint"]
.as_str()
.is_some_and(|f| f.starts_with("context:"))
})
})
.unwrap_or(false)
}
#[tokio::test]
async fn a_measured_context_mutation_promotes_and_applies_with_no_approval() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let stub = ContextStubMeasurer::new(context_baseline(), Ok(improved_context_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm1", false).await;
let d = context_detail(&result);
assert_eq!(d["status"], "applied", "{d}");
assert_eq!(
d["governance"], "promoted",
"the authorization here is the measurement, not a human: {d}"
);
assert_eq!(
d["rollback_patch"]["conversation_keep_recent"], original_keep as u64,
"{d}"
);
assert!(
result["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"{result}"
);
assert_eq!(keep_recent(&state).await, original_keep / 2);
assert!(
!has_context_pending(&result),
"a graded promotion must not also solicit an approval: {result}"
);
assert_eq!(
stub.keep_recents(),
vec![original_keep, original_keep / 2],
"baseline under the live config, candidate under the halved one"
);
assert_eq!(d["baseline_task_pass_rate"], 0.5, "{d}");
assert_eq!(d["candidate_task_pass_rate"], 0.5, "{d}");
assert_eq!(d["baseline_task_pass_denominator"], 12, "{d}");
assert_eq!(d["candidate_task_pass_denominator"], 12, "{d}");
assert_eq!(d["baseline_total_tokens"], 100_000, "{d}");
assert_eq!(d["candidate_total_tokens"], 80_000, "{d}");
let measured = &context_outcome(&result)["context_measured"];
assert_eq!(measured["status"], "measured", "{measured}");
assert_eq!(measured["grade_attempts"], 1, "{measured}");
assert_eq!(measured["model"], "stub-model", "{measured}");
assert_eq!(measured["split"], "held-out", "{measured}");
}
#[tokio::test]
async fn a_measured_context_regression_is_rejected_by_the_gate_and_applies_nothing() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let stub = ContextStubMeasurer::new(context_baseline(), Ok(regressed_context_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm2", false).await;
let d = context_detail(&result);
assert_eq!(d["status"], "rejected_by_gate", "{d}");
assert!(
d["reason"].as_str().unwrap().contains("TASK pass rate"),
"the rejection must name the guard that fired: {d}"
);
assert_eq!(context_outcome(&result)["applied"], 0, "{result}");
assert!(
!result["evolved"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "context"),
"{result}"
);
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
assert!(
!has_context_pending(&result),
"a measured regression must not be offered to an operator for approval: {result}"
);
assert_eq!(d["baseline_task_pass_rate"], 0.5, "{d}");
assert_eq!(d["candidate_task_pass_rate"], 0.25, "{d}");
}
#[tokio::test]
async fn a_failed_context_measurement_fabricates_nothing_and_backs_nothing_off() {
use car_server_core::evolution::{run_context_evolution, ContextBackoff};
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let stub = ContextStubMeasurer::new(
context_baseline(),
Err("the bench host ran out of disk staging the task suite".to_string()),
);
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm3", false).await;
let d = context_detail(&result);
assert_eq!(d["status"], "measurement_failed", "{d}");
assert!(
d["error"].as_str().unwrap().contains("ran out of disk"),
"{d}"
);
assert!(
d.get("baseline_task_pass_rate").is_none(),
"no verdict was reached, so there is nothing to audit it against: {d}"
);
assert_eq!(context_outcome(&result)["applied"], 0, "{result}");
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
assert!(
!has_context_pending(&result),
"a failed measurement is a broken instrument, not a proposal for review: {result}"
);
let engine = state.shared_memgine.as_ref().unwrap().clone();
let backoff = std::sync::Mutex::new(ContextBackoff::default());
let pending = std::sync::Mutex::new(Vec::new());
let request = serde_json::from_value(
serde_json::json!({ "model": "stub-model", "split": "held-out", "split_seed": 0 }),
)
.expect("HarnessMeasureRequest shape");
for tick in 1..=2u64 {
let out = run_context_evolution(
&engine,
&state,
false,
&pending,
Some((&backoff, tick)),
Some((stub.as_ref(), &request)),
)
.await
.unwrap_or_else(|e| panic!("tick {tick}: {e}"));
let detail = detail_for(
&serde_json::from_str::<serde_json::Value>(&out.summary).unwrap(),
"context_budget",
);
assert_eq!(
detail["status"], "measurement_failed",
"tick {tick} must retry the measurement rather than back the mutation off: {detail}"
);
}
}
#[tokio::test]
async fn dry_run_with_context_measure_replays_nothing_and_falls_back_to_the_human_gate() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let stub = ContextStubMeasurer::new(context_baseline(), Ok(improved_context_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm4", true).await;
let d = context_detail(&result);
assert_eq!(d["status"], "pending_approval", "{d}");
assert!(
stub.keep_recents().is_empty(),
"a dry run must spend no replay at all, got {:?}",
stub.keep_recents()
);
let reason = d["reason"].as_str().unwrap();
assert!(
reason.contains("dry_run") && reason.contains("paid side effect"),
"the reason must name the precondition that was missing: {reason}"
);
assert!(has_context_pending(&result), "{result}");
let measured = &context_outcome(&result)["context_measured"];
assert_eq!(measured["status"], "skipped_dry_run", "{measured}");
assert_eq!(measured["grade_attempts"], 0, "{measured}");
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
}
#[tokio::test]
async fn without_context_measure_no_replay_is_spent_and_no_measurement_is_reported() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let stub = ContextStubMeasurer::new(context_baseline(), Ok(improved_context_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_cycle(&mut ws, "cm5", false).await;
let d = context_detail(&result);
assert_eq!(d["status"], "pending_approval", "{d}");
assert!(stub.keep_recents().is_empty(), "no replay may be spent");
assert!(
context_outcome(&result).get("context_measured").is_none(),
"an unrequested measurement has nothing to report: {result}"
);
assert!(d["reason"].as_str().unwrap().contains("was absent"), "{d}");
}
#[tokio::test]
async fn context_measure_without_an_installed_measurer_errs() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let mut ws = connect(&state).await;
let resp = send_recv(
&mut ws,
serde_json::json!({
"jsonrpc": "2.0", "id": "cm6", "method": "evolution.run",
"params": { "context_measure": { "model": "stub-model" } }
}),
)
.await;
let err = resp["error"]["message"]
.as_str()
.unwrap_or_else(|| panic!("expected an error, got {resp}"));
assert!(err.contains("context_measure"), "{err}");
assert!(err.contains("no in-process harness"), "{err}");
}
#[tokio::test]
async fn a_failed_context_baseline_measurement_is_never_silently_swallowed() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let stub = ContextStubMeasurer::failing_baseline("bench backend unreachable");
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm7", false).await;
let d = context_detail(&result);
assert_eq!(d["status"], "measurement_failed", "{d}");
let error = d["error"].as_str().unwrap_or_default();
assert!(
error.contains("bench backend unreachable"),
"the failure must name what went wrong: {d}"
);
assert!(
error.contains("baseline"),
"and which half of the comparison died — a failed baseline and a failed \
candidate are different infrastructure problems: {d}"
);
assert_eq!(
stub.keep_recents(),
vec![original_keep],
"only the baseline replay may be spent"
);
assert!(
d.get("baseline_task_pass_rate").is_none(),
"a failed measurement must carry NO metrics: {d}"
);
assert_eq!(context_outcome(&result)["applied"], 0, "{result}");
assert!(
!result["evolved"]
.as_array()
.expect("evolved")
.iter()
.any(|v| v == "context"),
"{result}"
);
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
assert!(
!has_context_pending(&result),
"a failed measurement is a broken instrument, not a proposal for review: {result}"
);
}
#[tokio::test]
async fn a_shrunken_context_task_denominator_is_incomparable_and_applies_nothing() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let tokens_before = conversation_tokens(&state).await;
let stub = ContextStubMeasurer::new(context_baseline(), Ok(incomparable_context_candidate()));
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm8", false).await;
let d = context_detail(&result);
assert_eq!(
d["status"], "pending_approval",
"not `rejected_by_gate` — nothing says the candidate is bad, only that \
this evidence cannot decide it: {d}"
);
let reason = d["reason"].as_str().unwrap_or_default();
assert!(
reason.contains("12") && reason.contains("8"),
"the reason must name both denominators: {d}"
);
assert!(
d.get("rollback_patch").is_none(),
"nothing was applied, so there is nothing to roll back: {d}"
);
assert_eq!(context_outcome(&result)["applied"], 0, "{result}");
assert!(
!result["evolved"]
.as_array()
.expect("evolved")
.iter()
.any(|v| v == "context"),
"an undecidable comparison must not report context as evolved: {result}"
);
assert_eq!(keep_recent(&state).await, original_keep);
assert_eq!(conversation_tokens(&state).await, tokens_before);
assert!(has_context_pending(&result), "{result}");
assert_eq!(d["candidate_task_pass_denominator"], 8, "{d}");
assert_eq!(d["baseline_task_pass_denominator"], 12, "{d}");
let measured = &context_outcome(&result)["context_measured"];
assert_eq!(measured["status"], "measured", "{measured}");
assert_eq!(measured["grade_attempts"], 1, "{measured}");
}
#[tokio::test]
async fn a_context_base_that_moves_during_measurement_refuses_to_apply() {
let tmp = TempDir::new().unwrap();
let state = state_with_engine(tmp.path().join("journals"), saturated_engine());
let original_keep = keep_recent(&state).await;
let interloper_keep = 5;
assert!(interloper_keep != original_keep && interloper_keep != original_keep / 2);
let stub = ContextStubMeasurer::mutating_the_engine_between_replays(
context_baseline(),
improved_context_candidate(),
state
.shared_memgine
.as_ref()
.expect("shared engine")
.clone(),
interloper_keep,
);
state.set_harness_measurer(stub.clone());
let mut ws = connect(&state).await;
let result = run_context_measured(&mut ws, "cm9", false).await;
let d = context_detail(&result);
assert_eq!(d["status"], "config_moved_during_measurement", "{d}");
assert_eq!(
d["measured_under_conversation_keep_recent"], original_keep as u64,
"{d}"
);
assert_eq!(
d["current_conversation_keep_recent"], interloper_keep as u64,
"{d}"
);
let reason = d["reason"].as_str().unwrap_or_default();
assert!(
reason.contains(&original_keep.to_string())
&& reason.contains(&interloper_keep.to_string()),
"the reason must name the value the grade was measured under and the value live now: {d}"
);
assert!(
d.get("rollback_patch").is_none(),
"nothing was applied, so there is nothing to roll back: {d}"
);
assert_eq!(keep_recent(&state).await, interloper_keep);
assert_eq!(context_outcome(&result)["applied"], 0, "{result}");
assert!(
!result["evolved"]
.as_array()
.expect("evolved")
.iter()
.any(|v| v == "context"),
"a refused promotion must not report context as evolved: {result}"
);
assert!(
!has_context_pending(&result),
"an invalidated measurement must not solicit an approval: {result}"
);
assert_eq!(stub.keep_recents(), vec![original_keep, original_keep / 2]);
let measured = &context_outcome(&result)["context_measured"];
assert_eq!(measured["grade_attempts"], 1, "{measured}");
assert_eq!(d["baseline_task_pass_rate"], 0.5, "{d}");
assert_eq!(d["candidate_total_tokens"], 80_000, "{d}");
}