mod golden;
use golden::loop_generator::{generate_loop, AREEV_LOOP_NOW0_MS};
use golden::{
assert_golden, areev, areev_at, import_loop_golden, loop_bundle_path, loop_golden_dir,
loop_manifest, loop_manifest_path, GoldenDb,
};
use std::collections::BTreeSet;
use std::io::Write as IoWrite;
use tempfile::TempDir;
const T0: i64 = AREEV_LOOP_NOW0_MS;
const HOUR: i64 = 3_600_000;
const DAY: i64 = 86_400_000;
fn loop_cmd(db: &str, now: i64, args: &[&str]) -> (i32, String, String) {
let mut full: Vec<&str> = vec!["loop"];
full.extend_from_slice(args);
full.extend_from_slice(&["--db", db, "--ns", "agent", "--telemetry", "off"]);
areev_at(now, &full)
}
fn loop_ok(db: &str, now: i64, args: &[&str]) -> String {
let (code, out, err) = loop_cmd(db, now, args);
assert_eq!(code, 0, "loop {args:?} failed (exit {code}): {err}");
out
}
fn run_json(db: &str, now: i64, extra: &[&str]) -> serde_json::Value {
let mut args = vec!["run", "--format", "json"];
args.extend_from_slice(extra);
let out = loop_ok(db, now, &args);
serde_json::from_str(&out).unwrap_or_else(|e| panic!("run output not JSON ({e}): {out}"))
}
fn list_rows(db: &str, now: i64, extra: &[&str]) -> Vec<serde_json::Value> {
let mut args = vec!["list", "--format", "json"];
args.extend_from_slice(extra);
let out = loop_ok(db, now, &args);
serde_json::from_str(&out).unwrap_or_else(|e| panic!("list output not JSON ({e}): {out}"))
}
fn find_rec(rows: &[serde_json::Value], analyzer: &str, summary_needle: &str) -> String {
let hits: Vec<&serde_json::Value> = rows
.iter()
.filter(|r| {
r["analyzer"].as_str().unwrap_or("").contains(analyzer)
&& r["summary"].as_str().unwrap_or("").contains(summary_needle)
})
.collect();
assert_eq!(
hits.len(),
1,
"expected exactly one {analyzer} rec matching {summary_needle:?}, got {hits:?}"
);
hits[0]["hash"].as_str().unwrap().to_string()
}
fn import_and_run() -> (GoldenDb, serde_json::Value) {
let g = import_loop_golden();
let res = run_json(&g.db, T0, &[]);
assert_eq!(res["outcome"], "ran", "first run must execute: {res}");
(g, res)
}
fn find_python() -> Option<&'static str> {
["python3", "python"].into_iter().find(|c| {
std::process::Command::new(c)
.arg("--version")
.output()
.is_ok_and(|o| o.status.success())
})
}
fn recall_hook(db: &str, prompt: &str, extra: &[&str]) -> String {
use std::process::{Command, Stdio};
let mut args = vec!["recall-hook", "--db", db, "--ns", "agent", "--telemetry", "off"];
args.extend_from_slice(extra);
let mut child = Command::new(env!("CARGO_BIN_EXE_areev"))
.args(&args)
.env("AREEV_LOOP_NOW_MS", T0.to_string())
.env_remove("AREEV_LOOP_POLICY")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
.expect("spawn recall-hook");
let hook = serde_json::json!({ "prompt": prompt }).to_string();
child.stdin.as_mut().unwrap().write_all(hook.as_bytes()).unwrap();
let out = child.wait_with_output().unwrap();
assert!(out.status.success(), "recall-hook failed");
String::from_utf8_lossy(&out.stdout).to_string()
}
#[test]
fn loop_analyzer_registry_pinned() {
let g = import_loop_golden();
let out = loop_ok(&g.db, T0, &["analyzers"]);
assert_golden(&loop_golden_dir().join("analyzers.txt"), &out);
}
#[test]
fn loop_default_policy_pinned() {
let g = import_loop_golden();
let out = loop_ok(&g.db, T0, &["policy"]);
assert_golden(&loop_golden_dir().join("policy-default.json"), &out);
}
#[test]
fn loop_policy_file_echo_pinned() {
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let p = dir.path().join("policy.json");
std::fs::write(&p, GRANT_DUP_POLICY).unwrap();
let out = loop_ok(&g.db, T0, &["policy", "--policy", p.to_str().unwrap()]);
assert_golden(&loop_golden_dir().join("policy-granting.json"), &out);
}
#[test]
fn loop_first_run_result_pinned() {
let g = import_loop_golden();
let out = loop_ok(&g.db, T0, &["run", "--format", "json"]);
assert_golden(&loop_golden_dir().join("run-first.json"), &out);
}
#[test]
fn loop_queue_listings_pinned() {
let (g, _res) = import_and_run();
let json_out = loop_ok(&g.db, T0, &["list", "--format", "json"]);
assert_golden(&loop_golden_dir().join("list-pending.json"), &json_out);
let human_out = loop_ok(&g.db, T0, &["list"]);
assert_golden(&loop_golden_dir().join("list-pending.txt"), &human_out);
}
#[test]
fn loop_show_payloads_pinned() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let mut all = String::new();
for r in &rows {
all.push_str(&loop_ok(&g.db, T0, &["show", r["hash"].as_str().unwrap()]));
}
assert_golden(&loop_golden_dir().join("shows-pending.json"), &all);
}
#[test]
fn loop_evidence_hashes_resolve_to_manifest_grains() {
let m = loop_manifest();
let known: BTreeSet<&str> = m.grains.iter().map(|e| e.hash.as_str()).collect();
let (g, _res) = import_and_run();
for r in list_rows(&g.db, T0, &[]) {
let show = loop_ok(&g.db, T0, &["show", r["hash"].as_str().unwrap()]);
let payload: serde_json::Value = serde_json::from_str(&show).unwrap();
for ev in payload["evidence"].as_array().expect("evidence array") {
let h = ev.as_str().unwrap();
assert!(
known.contains(h),
"evidence {h} (rec {}) is not a manifest grain",
r["hash"]
);
}
}
}
#[test]
fn loop_status_health_pinned() {
let (g, _res) = import_and_run();
let out = loop_ok(&g.db, T0, &["--format", "json"]);
assert_golden(&loop_golden_dir().join("status-after-run.json"), &out);
}
#[test]
fn loop_second_run_dedups_everything() {
let (g, _res) = import_and_run();
let out = loop_ok(&g.db, T0, &["run", "--format", "json"]);
assert_golden(&loop_golden_dir().join("run-second.json"), &out);
}
#[test]
fn loop_reflect_full_sweep_stays_deduped() {
let (g, _res) = import_and_run();
let out = loop_ok(&g.db, T0, &["reflect", "--format", "json"]);
assert_golden(&loop_golden_dir().join("run-reflect.json"), &out);
}
#[test]
fn loop_min_new_gate_skips() {
let (g, _res) = import_and_run();
let out = loop_ok(&g.db, T0, &["run", "--min-new", "1", "--format", "json"]);
assert_golden(&loop_golden_dir().join("run-skip-min-new.json"), &out);
}
#[test]
fn loop_if_stale_gate() {
let (g, _res) = import_and_run();
let skipped = run_json(&g.db, T0 + HOUR, &["--if-stale", "6h"]);
assert_eq!(skipped["outcome"], "skipped");
assert_eq!(skipped["skip_reason"], "not_stale");
let ran = run_json(&g.db, T0 + 7 * HOUR, &["--if-stale", "6h"]);
assert_eq!(ran["outcome"], "ran");
assert_eq!(ran["stored"], 0, "everything already queued: {ran}");
}
#[test]
fn loop_now_seam_rejects_garbage() {
let g = import_loop_golden();
let out = std::process::Command::new(env!("CARGO_BIN_EXE_areev"))
.args(["loop", "--db", &g.db, "--ns", "agent", "--telemetry", "off"])
.env("AREEV_LOOP_NOW_MS", "not-a-timestamp")
.env_remove("AREEV_LOOP_POLICY")
.output()
.expect("spawn areev");
assert!(!out.status.success(), "garbled AREEV_LOOP_NOW_MS must not succeed");
assert!(
String::from_utf8_lossy(&out.stderr).contains("AREEV_LOOP_NOW_MS"),
"failure must name the seam"
);
}
#[test]
fn loop_lifecycle_approve_apply_rollback_repropose() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "contradiction_sweep", "\"sam\"");
loop_ok(&g.db, T0, &["approve", &rec, "--because", "resolve to the newest residency", "--actor", "user:reviewer"]);
loop_ok(&g.db, T0, &["apply", &rec, "--because", "supersede the stale value", "--actor", "user:reviewer"]);
let applied = list_rows(&g.db, T0, &["--status", "applied"]);
assert_eq!(applied.len(), 1, "exactly the sam rec is applied: {applied:?}");
let (ok, hist, err) = areev(&["history", "--subject", "sam", "--relation", "lives_in", "--db", &g.db, "--ns", "agent"]);
assert!(ok, "history failed: {err}");
assert!(hist.contains("berlin") && hist.contains("tokyo"), "chain should span both values: {hist}");
loop_ok(&g.db, T0, &["rollback", &rec, "--because", "keep both values for review", "--actor", "user:reviewer"]);
let rolled = list_rows(&g.db, T0, &["--status", "rolled_back"]);
assert_eq!(rolled.len(), 1, "the sam rec is rolled back: {rolled:?}");
let res = run_json(&g.db, T0 + HOUR, &[]);
assert_eq!(res["stored"], 1, "the contradiction must re-propose: {res}");
let rows = list_rows(&g.db, T0 + HOUR, &[]);
let re = find_rec(&rows, "contradiction_sweep", "\"sam\"");
assert_ne!(re, rec, "the re-proposal is a new grain, not the rolled-back one");
}
#[test]
fn loop_apply_requires_approval_first() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "contradiction_sweep", "\"sam\"");
let (code, _out, err) = loop_cmd(&g.db, T0, &["apply", &rec, "--because", "skip review"]);
assert_ne!(code, 0, "pending → applied must be refused for a human actor");
assert!(err.contains("approve first"), "expected the lifecycle error, got: {err}");
}
#[test]
fn loop_self_approval_blocked() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "contradiction_sweep", "\"sam\"");
let (code, _out, err) = loop_cmd(
&g.db,
T0,
&["approve", &rec, "--because", "lgtm", "--actor", "engine:loop.contradiction_sweep/1"],
);
assert_ne!(code, 0, "the creating actor must not approve its own proposal");
assert!(err.contains("created this recommendation"), "expected SelfApproval, got: {err}");
}
#[test]
fn loop_because_is_mandatory() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "skill_stall", "parse_invoices");
let (code, _out, err) = loop_cmd(&g.db, T0, &["approve", &rec]);
assert_ne!(code, 0);
assert!(err.contains("--because"), "missing BECAUSE must be named: {err}");
}
#[test]
fn loop_destructive_apply_gated_then_erases() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "staleness", "promo-black-friday");
loop_ok(&g.db, T0, &["approve", &rec, "--because", "the promo ended months ago", "--actor", "user:reviewer"]);
let (code, _out, err) = loop_cmd(&g.db, T0, &["apply", &rec, "--because", "expire it", "--actor", "user:reviewer"]);
assert_ne!(code, 0, "destructive apply must be gated");
assert!(err.contains("allow_destructive"), "gate must name the flag: {err}");
let exists = g.cal("agent", r#"EXISTS facts WHERE subject = "promo-black-friday""#);
assert_eq!(exists["exists"], true, "grain must survive the refused apply");
loop_ok(&g.db, T0, &["apply", &rec, "--because", "expire it", "--actor", "user:reviewer", "--allow-destructive"]);
let exists = g.cal("agent", r#"EXISTS facts WHERE subject = "promo-black-friday""#);
assert_eq!(exists["exists"], false, "expired grain must be tombstoned");
let (ok, out, _err) = areev(&["verify", "--db", &g.db]);
assert!(ok && out.contains("integrity: ok"), "verify after FORGET: {out}");
let (code, _out, err) = loop_cmd(&g.db, T0, &["rollback", &rec, "--because", "oops", "--actor", "user:reviewer"]);
assert_ne!(code, 0, "non-rollbackable apply must refuse rollback");
assert!(err.contains("non-rollbackable"), "expected the rollback error, got: {err}");
}
fn apply_sam_contradiction(g: &GoldenDb) -> String {
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "contradiction_sweep", "\"sam\"");
loop_ok(&g.db, T0, &["approve", &rec, "--because", "resolve to newest", "--actor", "user:reviewer"]);
loop_ok(&g.db, T0, &["apply", &rec, "--because", "resolve to newest", "--actor", "user:reviewer"]);
rec
}
#[test]
fn loop_outcome_held_across_horizons() {
let (g, _res) = import_and_run();
let _rec = apply_sam_contradiction(&g);
run_json(&g.db, T0 + DAY, &[]);
run_json(&g.db, T0 + 7 * DAY, &[]);
let out = loop_ok(&g.db, T0 + 7 * DAY, &["outcomes", "--format", "json"]);
assert_golden(&loop_golden_dir().join("outcomes-held.json"), &out);
}
#[test]
fn loop_outcome_regression_proposes_revert() {
let (g, _res) = import_and_run();
let rec = apply_sam_contradiction(&g);
let (ok, _out, err) = areev(&["add", "sam", "lives_in", "osaka", "--db", &g.db, "--ns", "agent"]);
assert!(ok, "seed regression: {err}");
let res = loop_ok(&g.db, T0 + DAY, &["run", "--format", "json"]);
assert_golden(&loop_golden_dir().join("run-after-regression.json"), &res);
let out = loop_ok(&g.db, T0 + DAY, &["outcomes", "--format", "json"]);
assert_golden(&loop_golden_dir().join("outcomes-regressed.json"), &out);
let rows = list_rows(&g.db, T0 + DAY, &[]);
let revert = rows
.iter()
.find(|r| r["analyzer"].as_str().unwrap_or("").contains("outcome_review"))
.unwrap_or_else(|| panic!("no revert proposal in {rows:?}"));
assert_eq!(revert["severity"], "high");
let show = loop_ok(&g.db, T0 + DAY, &["show", revert["hash"].as_str().unwrap()]);
let payload: serde_json::Value = serde_json::from_str(&show).unwrap();
assert_eq!(
payload["evidence"][0].as_str(),
Some(rec.as_str()),
"the revert must cite the applied recommendation"
);
}
#[test]
fn loop_reject_cooldown_suppresses_then_expires() {
let (g, _res) = import_and_run();
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "skill_stall", "parse_invoices");
loop_ok(&g.db, T0, &["reject", &rec, "--because", "long-tail skill, expected", "--actor", "user:reviewer"]);
let res = run_json(&g.db, T0 + HOUR, &[]);
assert_eq!(res["stored"], 0, "cooldown must suppress the re-proposal: {res}");
let res = run_json(&g.db, T0 + 8 * DAY, &[]);
assert_eq!(res["stored"], 1, "expired cooldown must re-propose: {res}");
let rows = list_rows(&g.db, T0 + 8 * DAY, &[]);
find_rec(&rows, "skill_stall", "parse_invoices");
}
const GRANT_DUP_POLICY: &str = r#"{
"auto_apply_enabled": true,
"auto_apply": [
{"analyzer": "loop.duplicate_sweep", "targets": ["memory"], "max_severity": "low"}
]
}"#;
const GRANT_ALL_POLICY: &str = r#"{
"auto_apply_enabled": true,
"auto_apply": [
{"analyzer": "loop.duplicate_sweep", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.contradiction_sweep", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.tool_failure", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.staleness", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.fork_surfacing", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.skill_stall", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.outcome_review", "targets": ["memory", "query"], "max_severity": "high"},
{"analyzer": "loop.llm", "targets": ["memory", "query"], "max_severity": "high"}
]
}"#;
fn write_policy(dir: &TempDir, body: &str) -> String {
let p = dir.path().join("policy.json");
std::fs::write(&p, body).unwrap();
p.to_str().unwrap().to_string()
}
#[test]
fn loop_auto_apply_grant_consolidates_duplicates() {
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let policy = write_policy(&dir, GRANT_DUP_POLICY);
let out = loop_ok(&g.db, T0, &["run", "--format", "json", "--policy", &policy]);
assert_golden(&loop_golden_dir().join("run-auto-apply.json"), &out);
let applied = list_rows(&g.db, T0, &["--status", "applied"]);
assert_eq!(applied.len(), 1, "only the exact-dup consolidation: {applied:?}");
assert!(applied[0]["summary"].as_str().unwrap().contains("exact-duplicate"));
let pending = list_rows(&g.db, T0, &[]);
assert!(
pending.iter().any(|r| r["summary"].as_str().unwrap().contains("near-duplicate")),
"near-dup must stay pending: {pending:?}"
);
let hist = areev(&["history", "--subject", "acme", "--relation", "tier", "--db", &g.db, "--ns", "agent"]);
assert!(hist.0, "history failed: {}", hist.2);
}
#[test]
fn loop_trust_floor_survives_maximal_policy() {
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let policy = write_policy(&dir, GRANT_ALL_POLICY);
let res: serde_json::Value = serde_json::from_str(&loop_ok(
&g.db,
T0,
&["run", "--format", "json", "--policy", &policy],
))
.unwrap();
assert_eq!(res["auto_applied"], 1, "trust floor breached: {res}");
}
#[test]
fn loop_closed_default_never_auto_applies() {
let (_g, res) = import_and_run();
assert_eq!(res["auto_applied"], 0, "no policy → nothing auto-applies: {res}");
}
#[test]
fn loop_fail_on_gate_exit_codes() {
let (g, _res) = import_and_run();
let (code, _out, err) = loop_cmd(&g.db, T0, &["list", "--fail-on", "high"]);
assert_eq!(code, 2, "pending high rec must exit 2: {err}");
let rows = list_rows(&g.db, T0, &[]);
let tool = find_rec(&rows, "tool_failure", "stripe_refund");
loop_ok(&g.db, T0, &["reject", &tool, "--because", "known upstream incident", "--actor", "user:reviewer"]);
let (code, _out, _err) = loop_cmd(&g.db, T0, &["list", "--fail-on", "high"]);
assert_eq!(code, 0, "no pending high rec left");
let (code, _out, _err) = loop_cmd(&g.db, T0, &["list", "--fail-on", "low"]);
assert_eq!(code, 2, "medium/low pendings still trip a low threshold");
}
#[test]
fn loop_recall_hook_injection_pinned() {
let (g, _res) = import_and_run();
let out = recall_hook(&g.db, "what do we know about sam", &["--with-loop"]);
assert!(
out.contains("sam lives_in tokyo") && out.contains("sam lives_in berlin"),
"memory render must surface both residency facts: {out}"
);
let block_at = out.find("Areev Loop:").unwrap_or_else(|| panic!("no loop block: {out}"));
assert_golden(&loop_golden_dir().join("recall-hook-loop-block.txt"), &out[block_at..]);
let without = recall_hook(&g.db, "what do we know about sam", &[]);
assert!(!without.contains("pending recommendation"), "flagless hook leaked areev-loop: {without}");
}
const FAKE_LLM_PY: &str = r#"
import sys, json
d = json.loads(sys.stdin.read())
op = d.get("op")
if op == "probe":
print(json.dumps({"model": "golden-fake-1"}))
elif op == "discover":
ev = (sorted(e["hash"] for e in d.get("evidence", []) if "sam" in e.get("text", ""))
or sorted(e["hash"] for e in d.get("evidence", []))[:1])
print(json.dumps({"recommendations": [{
"summary": "Residency facts conflict: sam is recorded in two cities",
"target": "entity:agent/sam",
"guidance": "confirm which residency is current before relying on either",
"evidence": ev,
"confidence": 0.9,
}]}))
elif op == "ground":
print(json.dumps({"results": [{"id": c["id"], "supported": True, "reason": "premises cited"}
for c in d.get("claims", [])]}))
elif op == "verify":
print(json.dumps({"results": [{"id": f["id"], "keep": True, "confidence": 0.9,
"reason": "two conflicting facts in evidence"}
for f in d.get("findings", [])]}))
else:
print(json.dumps({"notes": [{"target": "entity:agent/sam",
"guidance": "resolve to the most recent statement"}]}))
"#;
#[test]
fn loop_llm_reflection_end_to_end() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_llm.py");
std::fs::write(&script, FAKE_LLM_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let res = run_json(&g.db, T0, &["--llm-cmd", &cmd]);
assert_eq!(res["stored"], 12, "11 deterministic + 1 verified llm finding: {res}");
let rows = list_rows(&g.db, T0, &[]);
let llm = find_rec(&rows, "loop.llm", "Residency facts conflict");
let show: serde_json::Value =
serde_json::from_str(&loop_ok(&g.db, T0, &["show", &llm])).unwrap();
assert_eq!(show["evidence"].as_array().unwrap().len(), 2, "cites both sam facts: {show}");
let det = find_rec(&rows, "contradiction_sweep", "\"sam\"");
let det_show: serde_json::Value =
serde_json::from_str(&loop_ok(&g.db, T0, &["show", &det])).unwrap();
assert_eq!(det_show["analyzer"], "loop.contradiction_sweep/1");
let tiny_dir = TempDir::new().unwrap();
let tiny = tiny_dir.path().join("tiny.db").to_str().unwrap().to_string();
let (ok, _out, err) = areev(&["add", "sam", "prefers", "tea", "--db", &tiny, "--ns", "agent"]);
assert!(ok, "seed tiny memory: {err}");
let res = run_json(&tiny, T0, &["--llm-cmd", &cmd]);
assert_eq!(res["stored"], 1, "the llm draft is the only finding: {res}");
let out = recall_hook(&tiny, "what do we know about sam", &["--with-loop"]);
assert!(out.contains("[llm]"), "llm badge missing from hook injection: {out}");
let status = loop_ok(&g.db, T0, &[]);
assert!(status.contains("LLM findings: 1 surfaced"), "status: {status}");
loop_ok(&g.db, T0, &["approve", &llm, "--because", "genuine conflict", "--actor", "user:reviewer"]);
let status = loop_ok(&g.db, T0, &[]);
assert!(status.contains("100% approved"), "approval rate missing: {status}");
}
const FAKE_LESSON_LLM_PY: &str = r#"
import sys, json
d = json.loads(sys.stdin.read())
op = d.get("op")
if op == "probe":
print(json.dumps({"model": "golden-fake-1"}))
elif op == "discover":
ev = sorted(e["hash"] for e in d.get("evidence", []) if "sam" in e.get("text", ""))[:1] \
or sorted(e["hash"] for e in d.get("evidence", []))[:1]
print(json.dumps({"recommendations": [{
"summary": "residency keeps being asked twice",
"target": "entity:agent/sam",
"evidence": ev,
"confidence": 0.9,
"proposal": {"kind": "lesson", "lesson": "Confirm sam's current city before answering residency questions."},
}]}))
elif op == "ground":
print(json.dumps({"results": [{"id": c["id"], "supported": True, "reason": "premises cited"}
for c in d.get("claims", [])]}))
elif op == "verify":
print(json.dumps({"results": [{"id": f["id"], "keep": True, "confidence": 0.9,
"reason": "sound"} for f in d.get("findings", [])]}))
else:
print(json.dumps({"notes": []}))
"#;
fn journal_eval_runs(db: &str, dir: &TempDir, name: &str, runs: &[(&str, u64, i64)]) {
let rows: Vec<(&str, u64, i64, serde_json::Value)> =
runs.iter().map(|(r, p, at)| (*r, *p, *at, serde_json::json!({}))).collect();
journal_eval_runs_with(db, dir, name, &rows);
}
fn journal_eval_runs_with(db: &str, dir: &TempDir, name: &str, runs: &[(&str, u64, i64, serde_json::Value)]) {
let path = dir.path().join(format!("{name}.jsonl"));
let mut f = std::fs::File::create(&path).unwrap();
for (run_id, passed, at, extra) in runs {
let mut summary = serde_json::json!({"run_id": run_id, "passed": passed, "failed": 280 - passed});
for (k, v) in extra.as_object().unwrap() {
summary[k] = v.clone();
}
let summary = summary.to_string();
writeln!(
f,
r#"{{"subject":"evalset:adbuy","relation":"mg:eval_run","object":{},"created_at":{at}}}"#,
serde_json::Value::String(summary)
)
.unwrap();
}
let (ok, _out, err) = areev(&[
"migrate", "--from", "jsonl", "--file", path.to_str().unwrap(), "--db", db, "--ns", "agent:harness",
]);
assert!(ok, "journal eval runs: {err}");
}
#[test]
fn loop_outcome_high_water_baseline_end_to_end() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_lesson_llm.py");
std::fs::write(&script, FAKE_LESSON_LLM_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let policy = write_policy(
&dir,
r#"{"outcome_evalset": {"hash": "adbuy", "field": "passed", "higher_is_better": true,
"baseline": "high_water", "checkpoints": [{"after_runs": 1}]}}"#,
);
journal_eval_runs(&g.db, &dir, "before", &[
("eval-day-one", 35, T0 - 3 * DAY),
("eval-peak", 238, T0 - 2 * DAY),
("eval-fallen", 128, T0 - DAY),
]);
let res = run_json(&g.db, T0, &["--llm-cmd", &cmd, "--policy", &policy]);
assert_eq!(res["stored"], 12, "11 deterministic + the lesson: {res}");
let rows = list_rows(&g.db, T0, &[]);
let lesson = find_rec(&rows, "loop.llm", "residency keeps being asked twice");
let show: serde_json::Value = serde_json::from_str(&loop_ok(&g.db, T0, &["show", &lesson])).unwrap();
assert_eq!(show["metric"]["metric"], "evalset:adbuy:passed", "{show}");
assert_eq!(show["metric"]["baseline"], 128.0, "the proposal froze the newest run");
loop_ok(&g.db, T0, &["approve", &lesson, "--because", "reads fine", "--actor", "user:reviewer"]);
loop_ok(&g.db, T0 + HOUR, &["apply", &lesson, "--because", "try it", "--actor", "user:reviewer"]);
journal_eval_runs(&g.db, &dir, "after", &[("eval-after", 133, T0 + 2 * HOUR)]);
run_json(&g.db, T0 + 3 * HOUR, &["--policy", &policy]);
let out = loop_ok(&g.db, T0 + 3 * HOUR, &["outcomes", "--format", "json"]);
assert_golden(&loop_golden_dir().join("outcomes-high-water.json"), &out);
let outcomes: Vec<serde_json::Value> = serde_json::from_str(&out).unwrap();
let o = outcomes.iter().find(|o| o["rec_hash"] == lesson.as_str()).expect("the lesson was measured");
assert_eq!(o["verdict"], "regressed");
assert_eq!(o["baseline"], 238.0);
assert_eq!(o["current"], 133.0);
assert_eq!(o["baseline_kind"], "high_water");
assert_eq!(o["baseline_run_id"], "eval-peak");
assert_eq!(o["best_before"], 238.0);
let text = loop_ok(&g.db, T0 + 3 * HOUR, &["outcomes"]);
assert!(text.contains("best_before 238") && text.contains("baseline=high_water (eval-peak)"), "{text}");
let rows = list_rows(&g.db, T0 + 3 * HOUR, &[]);
let revert = rows
.iter()
.find(|r| r["analyzer"].as_str().unwrap_or("").contains("outcome_review"))
.unwrap_or_else(|| panic!("no revert proposed: {rows:?}"));
let summary = revert["summary"].as_str().unwrap_or("");
assert!(summary.contains("eval-peak") && summary.contains("238") && summary.contains("133"), "{summary}");
}
#[test]
fn loop_outcome_min_effect_end_to_end() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_lesson_llm.py");
std::fs::write(&script, FAKE_LESSON_LLM_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let policy = write_policy(
&dir,
r#"{"outcome_evalset": {"hash": "adbuy", "field": "passed", "higher_is_better": true,
"min_effect": {"count": 5}, "checkpoints": [{"after_runs": 1}]}}"#,
);
journal_eval_runs(&g.db, &dir, "before", &[("eval-before", 238, T0 - DAY)]);
run_json(&g.db, T0, &["--llm-cmd", &cmd, "--policy", &policy]);
let rows = list_rows(&g.db, T0, &[]);
let lesson = find_rec(&rows, "loop.llm", "residency keeps being asked twice");
loop_ok(&g.db, T0, &["approve", &lesson, "--because", "reads fine", "--actor", "user:reviewer"]);
loop_ok(&g.db, T0 + HOUR, &["apply", &lesson, "--because", "try it", "--actor", "user:reviewer"]);
journal_eval_runs(&g.db, &dir, "after", &[("eval-after", 234, T0 + 2 * HOUR)]);
run_json(&g.db, T0 + 3 * HOUR, &["--policy", &policy]);
let out = loop_ok(&g.db, T0 + 3 * HOUR, &["outcomes", "--format", "json"]);
assert_golden(&loop_golden_dir().join("outcomes-min-effect.json"), &out);
let outcomes: Vec<serde_json::Value> = serde_json::from_str(&out).unwrap();
let o = outcomes.iter().find(|o| o["rec_hash"] == lesson.as_str()).expect("measured");
assert_eq!((o["verdict"].as_str(), o["tolerance"].as_f64()), (Some("held"), Some(5.0)), "{o}");
let rows = list_rows(&g.db, T0 + 3 * HOUR, &[]);
assert!(
!rows.iter().any(|r| r["analyzer"].as_str().unwrap_or("").contains("outcome_review")),
"a dip inside the floor drafts no revert: {rows:?}"
);
}
#[test]
fn loop_outcome_cost_bound_end_to_end() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_lesson_llm.py");
std::fs::write(&script, FAKE_LESSON_LLM_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let policy = write_policy(
&dir,
r#"{"outcome_evalset": {"hash": "adbuy", "field": "passed", "higher_is_better": true,
"cost": {"field": "tokens", "max_increase_ratio": 1.5},
"checkpoints": [{"after_runs": 1}]}}"#,
);
journal_eval_runs_with(&g.db, &dir, "before", &[
("eval-before", 102, T0 - DAY, serde_json::json!({"effects": 280, "input_tokens": 800, "output_tokens": 200, "wall_ms": 4000})),
]);
run_json(&g.db, T0, &["--llm-cmd", &cmd, "--policy", &policy]);
let rows = list_rows(&g.db, T0, &[]);
let lesson = find_rec(&rows, "loop.llm", "residency keeps being asked twice");
loop_ok(&g.db, T0, &["approve", &lesson, "--because", "reads fine", "--actor", "user:reviewer"]);
loop_ok(&g.db, T0 + HOUR, &["apply", &lesson, "--because", "try it", "--actor", "user:reviewer"]);
journal_eval_runs_with(&g.db, &dir, "after", &[
("eval-after", 104, T0 + 2 * HOUR, serde_json::json!({"effects": 840, "input_tokens": 1300, "output_tokens": 300, "wall_ms": 12000})),
]);
run_json(&g.db, T0 + 3 * HOUR, &["--policy", &policy]);
let out = loop_ok(&g.db, T0 + 3 * HOUR, &["outcomes", "--format", "json"]);
assert_golden(&loop_golden_dir().join("outcomes-cost.json"), &out);
let outcomes: Vec<serde_json::Value> = serde_json::from_str(&out).unwrap();
let o = outcomes.iter().find(|o| o["rec_hash"] == lesson.as_str()).expect("measured");
assert_eq!(o["verdict"], "held_costlier", "{o}");
assert_eq!(o["current_run_id"], "eval-after");
assert_eq!(o["cost"]["field"], "tokens");
assert_eq!(o["cost"]["baseline"], 1000.0);
assert_eq!(o["cost"]["current"], 1600.0);
assert_eq!(o["cost"]["status"], "breached");
let text = loop_ok(&g.db, T0 + 3 * HOUR, &["outcomes"]);
assert!(text.contains("[held_costlier]") && text.contains("cost tokens 1000 → 1600 ×1.60 [breached, bound ×1.5]"), "{text}");
let rows = list_rows(&g.db, T0 + 3 * HOUR, &[]);
let flags: Vec<_> = rows
.iter()
.filter(|r| r["analyzer"].as_str().unwrap_or("").contains("outcome_review"))
.collect();
assert_eq!(flags.len(), 1, "one advisory finding: {rows:?}");
assert_eq!(flags[0]["severity"], "medium", "{}", flags[0]);
let summary = flags[0]["summary"].as_str().unwrap_or("");
assert!(summary.contains("held") && !summary.contains("regressed"), "{summary}");
assert!(summary.contains("eval-before") && summary.contains("eval-after") && summary.contains("1600"), "{summary}");
}
#[test]
fn loop_near_duplicate_lesson_is_flagged_end_to_end() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_lesson_llm.py");
std::fs::write(&script, FAKE_LESSON_LLM_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let path = dir.path().join("lesson.jsonl");
std::fs::write(
&path,
format!(
r#"{{"subject":"sam","relation":"lesson","object":"Confirm sam's current city before answering any residency question.","created_at":{}}}"#,
T0 - DAY
),
)
.unwrap();
let (ok, _out, err) = areev(&[
"migrate", "--from", "jsonl", "--file", path.to_str().unwrap(), "--db", &g.db, "--ns", "agent",
]);
assert!(ok, "seed the live lesson: {err}");
let res = run_json(&g.db, T0, &["--llm-cmd", &cmd]);
assert_eq!(res["stored"], 12, "flag mode: the near-duplicate still reaches the queue: {res}");
let rows = list_rows(&g.db, T0, &[]);
let row = rows
.iter()
.find(|r| r["analyzer"] == "loop.llm/1")
.unwrap_or_else(|| panic!("no llm row: {rows:?}"));
let near = row["near_duplicate_of"].as_array().expect("the listing carries near_duplicate_of");
assert_eq!(near.len(), 1, "{row}");
assert_eq!(near[0]["method"], "jaccard", "keyless: the T0 floor");
assert!(near[0]["score"].as_f64().unwrap() >= 0.6, "{row}");
assert!(row["summary"].as_str().unwrap().contains("NEAR-DUPLICATE"), "{row}");
let json = loop_ok(&g.db, T0, &["list", "--format", "json", "--status", "pending"]);
let rows: Vec<serde_json::Value> = serde_json::from_str(&json).unwrap();
let llm: Vec<&serde_json::Value> = rows.iter().filter(|r| r["analyzer"] == "loop.llm/1").collect();
assert_golden(&loop_golden_dir().join("list-near-duplicate.json"), &serde_json::to_string(&llm).unwrap());
let g2 = import_loop_golden();
let (ok, _out, err) = areev(&[
"migrate", "--from", "jsonl", "--file", path.to_str().unwrap(), "--db", &g2.db, "--ns", "agent",
]);
assert!(ok, "{err}");
let policy = write_policy(&dir, r#"{"near_duplicate": "suppress"}"#);
let res = run_json(&g2.db, T0, &["--llm-cmd", &cmd, "--policy", &policy]);
assert_eq!(res["stored"], 11, "the near-duplicate is dropped before the queue: {res}");
assert_eq!(res["llm_funnel"]["dropped_near_duplicate"], 1, "{res}");
assert!(list_rows(&g2.db, T0, &[]).iter().all(|r| r["analyzer"] != "loop.llm/1"));
}
#[test]
fn loop_replay_identity_reproduces_the_queue_with_zero_writes() {
let (g, _res) = import_and_run();
let dir = TempDir::new().unwrap();
let cfg = dir.path().join("candidate.json");
std::fs::write(&cfg, "{}").unwrap();
let live: BTreeSet<String> = list_rows(&g.db, T0, &[])
.iter()
.map(|r| r["hash"].as_str().unwrap().to_string())
.collect();
let out = loop_ok(&g.db, T0, &["replay", "--config", cfg.to_str().unwrap(), "--format", "json"]);
assert_golden(&loop_golden_dir().join("replay-identity.json"), &out);
let v: serde_json::Value = serde_json::from_str(&out).unwrap();
assert_eq!(v["steps"], serde_json::json!([T0]));
assert_eq!(v["oplog_len"]["before"], v["oplog_len"]["after"], "zero writes: {}", v["oplog_len"]);
for arm in ["incumbent", "candidate"] {
let addrs: BTreeSet<String> = v[arm]["findings"]
.as_array()
.unwrap()
.iter()
.map(|f| f["address"].as_str().expect("the adapter names the address").to_string())
.collect();
assert_eq!(addrs, live, "{arm}: the would-be grains ARE the stored grains");
assert!(v[arm]["findings"].as_array().unwrap().iter().all(|f| f["recorded"] == "never_reviewed"));
}
assert_eq!(v["not_replayed"], serde_json::json!([]), "{}", v["not_replayed"]);
std::fs::write(&cfg, r#"{"config": {"loop.contradiction_sweep/1": {"enabled": false}}}"#).unwrap();
let out = loop_ok(&g.db, T0, &["replay", "--config", cfg.to_str().unwrap(), "--format", "json"]);
let v: serde_json::Value = serde_json::from_str(&out).unwrap();
assert_eq!(v["incumbent"]["total"]["findings"], live.len());
assert!(v["candidate"]["per_analyzer"].get("loop.contradiction_sweep/1").is_none(), "{v}");
assert_eq!(v["candidate"]["skipped"]["loop.contradiction_sweep/1"], "disabled");
let text = loop_ok(&g.db, T0, &["replay", "--config", cfg.to_str().unwrap()]);
assert!(text.contains("incumbent") && text.contains("candidate") && text.contains("op-log"), "{text}");
assert!(text.contains("(unchanged)"), "{text}");
let after = (T0 + 1).to_string();
let (code, _out, err) = loop_cmd(&g.db, T0 + HOUR, &["replay", "--config", cfg.to_str().unwrap(), "--since", &after]);
assert_ne!(code, 0);
assert!(err.contains("no step"), "{err}");
std::fs::write(&cfg, r#"{"analyzers": {}}"#).unwrap();
let (code, _out, err) = loop_cmd(&g.db, T0, &["replay", "--config", cfg.to_str().unwrap()]);
assert_ne!(code, 0);
assert!(err.contains("unknown field"), "{err}");
}
#[test]
#[cfg(not(windows))]
fn loop_plan_revision_is_rehearsed_and_a_worse_one_is_refused() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let (ok, out, err) = areev(&["run", "--db", &g.db, "--ns", "agent", "demo"]);
assert!(ok, "{err}");
let wf = out
.lines()
.find_map(|l| l.strip_prefix("demo plan seeded (workflow "))
.and_then(|l| l.strip_suffix(")"))
.expect("workflow hash")
.to_string();
for id in ["demo-1", "demo-2", "demo-3"] {
let (ok, out, err) = areev(&[
"run", "--db", &g.db, "--ns", "agent", "start", "--workflow", &wf, "--run-id", id,
"--input", r#"{"who":"world"}"#, "--tool-cmd", r#"printf '{"greeting":"hello"}'"#,
]);
assert!(ok, "start {id}: {err}");
let envelope: serde_json::Value = serde_json::from_str(out.trim()).unwrap();
let ask = envelope["asks"][0]["tool_call_id"].as_str().unwrap().to_string();
let (ok, _out, err) = areev(&[
"run", "--db", &g.db, "--ns", "agent", "respond", "--run-id", id, "--ask", &ask,
"--result", r#"{"approved":true}"#, "--as", "user:officer",
]);
assert!(ok, "respond {id}: {err}");
let (ok, out, err) = areev(&["run", "--db", &g.db, "--ns", "agent", "resume", "--run-id", id]);
assert!(ok && out.contains("Completed"), "resume {id}: {err}\n{out}");
}
let script = dir.path().join("fake_plan_llm.py");
std::fs::write(&script, format!(r#"
import sys, json
d = json.loads(sys.stdin.read())
op = d.get("op")
if op == "probe":
print(json.dumps({{"model": "golden-fake-1"}}))
elif op == "discover":
ev = sorted(e["hash"] for e in d.get("evidence", []))[:1]
which = "{{WHICH}}"
if which == "harmless":
edits = [{{"path": "retries.greet", "from": None, "to": 1}}]
else:
edits = [{{"path": "edges.0.cond", "from": None, "to": "who == \"nobody\""}}]
print(json.dumps({{"recommendations": [{{
"summary": "the demo plan needs a tweak",
"target": "grain:{wf}",
"evidence": ev,
"confidence": 0.9,
"proposal": {{"kind": "plan_revision", "edits": edits}},
}}]}}))
elif op == "ground":
print(json.dumps({{"results": [{{"id": c["id"], "supported": True, "reason": "ok"}} for c in d.get("claims", [])]}}))
elif op == "verify":
print(json.dumps({{"results": [{{"id": f["id"], "keep": True, "confidence": 0.9, "reason": "ok"}} for f in d.get("findings", [])]}}))
else:
print(json.dumps({{"notes": []}}))
"#)).unwrap();
let policy = write_policy(&dir, r#"{"plan_replay": {"min_runs": 3, "require_no_worse": true}}"#);
let with = |which: &str| -> String {
let p = dir.path().join(format!("fake_{which}.py"));
std::fs::write(&p, std::fs::read_to_string(&script).unwrap().replace("{WHICH}", which)).unwrap();
format!("{py} {}", p.display())
};
run_json(&g.db, T0, &["--llm-cmd", &with("harmless"), "--policy", &policy]);
let rows = list_rows(&g.db, T0, &[]);
let rec = find_rec(&rows, "loop.llm", "revise plan");
let show: serde_json::Value = serde_json::from_str(&loop_ok(&g.db, T0, &["show", &rec])).unwrap();
assert_eq!(show["rollbackable"], true, "{show}");
assert_eq!(show["replay"]["totals"]["runs"], 3, "rehearsed against all three: {show}");
assert_eq!(show["replay"]["no_worse"], true);
assert_eq!(show["replay"]["runs"][0]["candidate_outcome"], "completed");
assert_eq!(show["replay"]["effect_dispatches"], 0);
let g2 = import_loop_golden();
let (ok, out, err) = areev(&["run", "--db", &g2.db, "--ns", "agent", "demo"]);
assert!(ok, "{err}");
assert!(out.contains(&wf), "the demo plan is content-addressed: same hash");
for id in ["demo-1", "demo-2", "demo-3"] {
let (ok, out, err) = areev(&[
"run", "--db", &g2.db, "--ns", "agent", "start", "--workflow", &wf, "--run-id", id,
"--input", r#"{"who":"world"}"#, "--tool-cmd", r#"printf '{"greeting":"hello"}'"#,
]);
assert!(ok, "start {id}: {err}");
let envelope: serde_json::Value = serde_json::from_str(out.trim()).unwrap();
let ask = envelope["asks"][0]["tool_call_id"].as_str().unwrap().to_string();
let (ok, _out, err) = areev(&[
"run", "--db", &g2.db, "--ns", "agent", "respond", "--run-id", id, "--ask", &ask,
"--result", r#"{"approved":true}"#, "--as", "user:officer",
]);
assert!(ok, "{err}");
let (ok, _out, err) = areev(&["run", "--db", &g2.db, "--ns", "agent", "resume", "--run-id", id]);
assert!(ok, "{err}");
}
run_json(&g2.db, T0, &["--llm-cmd", &with("worse"), "--policy", &policy]);
let rows = list_rows(&g2.db, T0, &[]);
let rec = find_rec(&rows, "loop.llm", "NOT applicable");
let show: serde_json::Value = serde_json::from_str(&loop_ok(&g2.db, T0, &["show", &rec])).unwrap();
assert_eq!(show["rollbackable"], false, "{show}");
let summary = show["summary"].as_str().unwrap();
assert!(summary.contains("demo-1") && summary.contains("completed → stalled"), "{summary}");
assert_eq!(show["replay"]["totals"]["worse"], 3, "{show}");
assert_eq!(show["replay"]["no_worse"], false);
}
#[test]
fn loop_llm_findings_never_auto_apply() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_llm.py");
std::fs::write(&script, FAKE_LLM_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let policy = write_policy(&dir, GRANT_ALL_POLICY);
let res = run_json(&g.db, T0, &["--llm-cmd", &cmd, "--policy", &policy]);
assert_eq!(res["stored"], 12, "{res}");
assert_eq!(res["auto_applied"], 1, "only the builtin consolidation — never the llm rec: {res}");
}
const FAKE_ANALYZER_PY: &str = r#"
import sys, json
d = json.loads(sys.stdin.read())
if d.get("op") == "probe":
print(json.dumps({"id": "golden.pii/1", "title": "PII scan",
"description": "golden external analyzer"}))
else:
kai = sorted(g["hash"] for g in d.get("grains", [])
if g.get("fields", {}).get("subject") == "kai")
print(json.dumps({"findings": [{
"target": "entity:agent/kai",
"summary": "contact preference may be personal data - review retention",
"severity": "high",
"evidence": kai,
"confidence": 0.8,
}]}))
"#;
#[test]
fn loop_external_analyzer_advisory_only() {
let Some(py) = find_python() else {
eprintln!("skipping: no python on PATH");
return;
};
let g = import_loop_golden();
let dir = TempDir::new().unwrap();
let script = dir.path().join("fake_analyzer.py");
std::fs::write(&script, FAKE_ANALYZER_PY).unwrap();
let cmd = format!("{py} {}", script.display());
let listing = loop_ok(&g.db, T0, &["analyzers", "--analyzer-cmd", &cmd]);
assert!(listing.contains("golden.pii/1"), "external analyzer missing: {listing}");
assert!(listing.contains("command"), "trust class must be visible: {listing}");
let policy = write_policy(&dir, GRANT_ALL_POLICY);
let res = run_json(&g.db, T0, &["--analyzer-cmd", &cmd, "--policy", &policy]);
assert_eq!(res["stored"], 12, "11 builtin + 1 external: {res}");
assert_eq!(res["auto_applied"], 1, "external finding must never auto-apply: {res}");
assert!(
res["analyzers_run"].as_array().unwrap().iter().any(|a| a == "golden.pii/1"),
"external analyzer must appear in analyzers_run: {res}"
);
let rows = list_rows(&g.db, T0, &[]);
let ext = find_rec(&rows, "golden.pii", "personal data");
let show: serde_json::Value =
serde_json::from_str(&loop_ok(&g.db, T0, &["show", &ext])).unwrap();
assert_eq!(show["severity"], "high");
let out = recall_hook(&g.db, "what do we know about kai", &["--with-loop"]);
assert!(out.contains("[external]"), "external badge missing: {out}");
}
#[test]
fn loop_telemetry_fed_analyzers_fire_on_live_rollups() {
let g = import_loop_golden();
for _ in 0..3 {
let (ok, out, err) = areev(&[
"search", "--db", &g.db, "--ns", "agent",
"--query", "quarterly carbon report deadline", "-k", "3",
]);
assert!(ok, "search failed: {err}");
assert!(out.trim().is_empty(), "gap query must return nothing: {out}");
}
for _ in 0..20 {
let payload = g.cal(
"agent",
r#"ASSEMBLE "t" FROM a: (RECALL facts WHERE subject = "sam") BUDGET 10 tokens FORMAT sml"#,
);
assert!(payload["grain_count"].as_i64() < Some(2), "budget must drop a grain: {payload}");
}
let out = std::process::Command::new(env!("CARGO_BIN_EXE_areev"))
.args(["loop", "run", "--format", "json", "--db", &g.db, "--ns", "agent"])
.env("AREEV_LOOP_NOW_MS", T0.to_string())
.env_remove("AREEV_LOOP_POLICY")
.output()
.expect("spawn areev");
assert!(out.status.success(), "telemetry run failed: {}", String::from_utf8_lossy(&out.stderr));
let res: serde_json::Value =
serde_json::from_str(&String::from_utf8_lossy(&out.stdout)).unwrap();
assert_eq!(res["stored"], 17, "11 deterministic + 4 cold + gap + budget: {res}");
for a in ["loop.cold_grains/1", "loop.coverage_gap/1", "loop.budget_pressure/1"] {
assert!(
res["analyzers_run"].as_array().unwrap().iter().any(|x| x == a),
"{a} must run with telemetry attached: {res}"
);
}
let rows = list_rows(&g.db, T0, &[]);
let cold = rows.iter().filter(|r| r["analyzer"].as_str().unwrap().contains("cold_grains")).count();
assert_eq!(cold, 4, "old never-recalled facts: {rows:?}");
find_rec(&rows, "coverage_gap", "quarterly carbon report deadline");
find_rec(&rows, "budget_pressure", "100% of 20 recalls");
}
#[test]
fn loop_cli_mcp_parity() {
use std::process::{Command, Stdio};
let (g_cli, _res) = import_and_run();
let cli_hashes: BTreeSet<String> = list_rows(&g_cli.db, T0, &[])
.iter()
.map(|r| r["hash"].as_str().unwrap().to_string())
.collect();
let g_mcp = import_loop_golden();
let rpc = |id: u64, method: &str, params: serde_json::Value| {
serde_json::json!({"jsonrpc": "2.0", "id": id, "method": method, "params": params})
.to_string()
};
let mut child = Command::new(env!("CARGO_BIN_EXE_areev"))
.args(["serve", "--mcp", "--db", &g_mcp.db, "--ns", "agent", "--telemetry", "off"])
.env("AREEV_LOOP_NOW_MS", T0.to_string())
.env_remove("AREEV_LOOP_POLICY")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
.expect("spawn mcp server");
{
let stdin = child.stdin.as_mut().unwrap();
writeln!(
stdin,
"{}",
rpc(1, "initialize", serde_json::json!({
"protocolVersion": "2025-06-18", "capabilities": {},
"clientInfo": {"name": "golden", "version": "0"}}))
)
.unwrap();
writeln!(stdin, r#"{{"jsonrpc":"2.0","method":"notifications/initialized"}}"#).unwrap();
writeln!(
stdin,
"{}",
rpc(2, "tools/call", serde_json::json!({
"name": "areev_loop", "arguments": {}}))
)
.unwrap();
}
let out = child.wait_with_output().expect("mcp server exit");
assert!(out.status.success());
let resp = String::from_utf8_lossy(&out.stdout)
.lines()
.filter_map(|l| serde_json::from_str::<serde_json::Value>(l).ok())
.find(|v| v["id"] == 2)
.expect("areev-loop response");
assert_ne!(resp["result"]["isError"], true, "mcp areev-loop errored: {resp}");
let text = resp["result"]["content"][0]["text"].as_str().expect("content text");
let payload: serde_json::Value = serde_json::from_str(text).expect("mcp payload json");
let mcp_hashes: BTreeSet<String> = payload["pending"]
.as_array()
.expect("pending array")
.iter()
.map(|r| r["hash"].as_str().unwrap().to_string())
.collect();
assert_eq!(
cli_hashes, mcp_hashes,
"CLI and MCP produced different recommendation content addresses"
);
}
#[test]
fn loop_import_verifies_clean() {
let g = import_loop_golden();
let (ok, out, err) = areev(&["verify", "--db", &g.db]);
assert!(ok, "verify failed: {err}");
assert!(out.contains("integrity: ok"), "bad verify: {out}");
}
#[test]
fn loop_fork_survives_bundle_roundtrip() {
let g = import_loop_golden();
let (ok, out, err) = areev(&["forks", "--db", &g.db]);
assert!(ok, "forks failed: {err}");
assert!(
out.contains("deploy") && out.contains("region"),
"deploy/region fork lost in export/import: {out}"
);
}
#[test]
fn loop_manifest_hashes_stable() {
let committed = loop_manifest();
let dir = TempDir::new().unwrap();
let fresh = generate_loop(dir.path(), &dir.path().join("fresh.bundle"));
assert_eq!(fresh.total_grains, committed.total_grains, "grain count drifted");
for (f, c) in fresh.grains.iter().zip(committed.grains.iter()) {
assert_eq!(
f.hash, c.hash,
"content address drifted for '{}' — canonical serialization changed?",
c.desc
);
}
}
#[test]
#[ignore = "regenerates committed golden files; run explicitly and commit the diff"]
fn bless_loop_golden_dataset() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(golden::dataset_dir()).unwrap();
let m = generate_loop(dir.path(), &loop_bundle_path());
std::fs::write(
loop_manifest_path(),
serde_json::to_string_pretty(&m.to_json()).unwrap() + "\n",
)
.unwrap();
eprintln!(
"blessed {} grains -> {} + {}",
m.total_grains,
loop_bundle_path().display(),
loop_manifest_path().display()
);
}