use assert_cmd::Command;
use predicates::prelude::PredicateBooleanExt;
use std::path::Path;
fn aristo_in(dir: &Path) -> Command {
let mut cmd = Command::cargo_bin("aristo").unwrap();
cmd.current_dir(dir);
cmd
}
fn seed_cluster(root: &Path, key: &str, sibling: &str) {
let dir = root.join(".aristo/canon-suggestions-queue/pending");
std::fs::create_dir_all(&dir).unwrap();
let body = format!(
"for_canon_ids = [\"primary_for_{key}\"]\n\
discovered_at = \"2026-06-05T00:00:00Z\"\n\n\
[objective]\ncanon_id = \"{key}\"\nversion = \"v0.1.0\"\n\
canonical_text = \"objective text\"\nscope = \"turso\"\n\
prefix_tier = \"kanon:\"\nbacked_by = \"\"\ndisposition = \"open\"\n\n\
[[siblings]]\ncanon_id = \"{sibling}\"\nversion = \"v0.1.0\"\n\
canonical_text = \"sibling text\"\nscope = \"turso\"\n\
prefix_tier = \"aristos:\"\nbacked_by = \"golden model\"\n\
disposition = \"open\"\n"
);
std::fs::write(dir.join(format!("{key}.toml")), body).unwrap();
}
const SOURCE: &str = r#"
#[aristo::intent(
"a commit frame must reach stable storage via fsync before durable",
id = "wal_commit_durable_invariant"
)]
pub fn commit() {}
"#;
fn setup_source(root: &Path) {
std::fs::create_dir_all(root.join("src")).unwrap();
std::fs::write(root.join("src/lib.rs"), SOURCE).unwrap();
std::fs::write(
root.join("Cargo.toml"),
"[package]\nname = \"sandbox\"\nversion = \"0.0.1\"\nedition = \"2021\"\n",
)
.unwrap();
}
#[test]
fn skip_canon_mode_runs_no_match() {
let tmp = tempfile::tempdir().unwrap();
aristo_in(tmp.path()).arg("init").assert().success();
setup_source(tmp.path());
aristo_in(tmp.path())
.args(["stamp", "--skip-canon"])
.assert()
.success()
.stdout(predicates::str::contains("canon-match: skipped"));
assert!(
!tmp.path()
.join(".aristo/canon-suggestions-queue/pending")
.exists()
|| std::fs::read_dir(tmp.path().join(".aristo/canon-suggestions-queue/pending"))
.map(|mut d| d.next().is_none())
.unwrap_or(true),
"skip-canon must not populate the suggestions queue"
);
assert!(
!tmp.path().join(".aristo/canon-matches.toml").exists(),
"skip-canon must not write the match cache"
);
}
#[test]
fn filter_parent_scopes_to_one_cluster() {
let tmp = tempfile::tempdir().unwrap();
aristo_in(tmp.path()).arg("init").assert().success();
seed_cluster(
tmp.path(),
"wal_protocol_correctness",
"wal_find_frame_range_invariant",
);
seed_cluster(
tmp.path(),
"storage_compaction_correctness",
"vacuum_atomic_under_crash",
);
aristo_in(tmp.path())
.args(["canon", "suggestions"])
.assert()
.success()
.stdout(predicates::str::contains("2 cluster(s)"));
aristo_in(tmp.path())
.args([
"canon",
"suggestions",
"--filter",
"parent=wal_protocol_correctness",
])
.assert()
.success()
.stdout(predicates::str::contains("1 cluster(s)"))
.stdout(predicates::str::contains("wal_protocol_correctness"))
.stdout(predicates::str::contains("storage_compaction_correctness").not());
}
#[test]
fn filter_parent_accepts_kanon_prefixed_objective() {
let tmp = tempfile::tempdir().unwrap();
aristo_in(tmp.path()).arg("init").assert().success();
seed_cluster(
tmp.path(),
"wal_protocol_correctness",
"wal_find_frame_range_invariant",
);
aristo_in(tmp.path())
.args([
"canon",
"suggestions",
"--filter",
"parent=kanon:wal_protocol_correctness",
])
.assert()
.success()
.stdout(predicates::str::contains("1 cluster(s)"))
.stdout(predicates::str::contains("wal_protocol_correctness"));
}
#[test]
fn queue_status_counts_emit_no_session_no_writes() {
let tmp = tempfile::tempdir().unwrap();
aristo_in(tmp.path()).arg("init").assert().success();
seed_cluster(
tmp.path(),
"wal_protocol_correctness",
"wal_find_frame_range_invariant",
);
let out = aristo_in(tmp.path())
.args(["canon", "suggestions", "--counts"])
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
let v: serde_json::Value = serde_json::from_str(stdout.trim()).unwrap();
assert_eq!(v["suggestions"]["new"], 1, "got: {v}");
assert!(
!tmp.path().join(".aristo/sessions/.active").exists(),
"status mode must not open a session"
);
}
#[test]
fn matches_only_and_suggestions_only_each_skip_the_other_stage() {
let tmp = tempfile::tempdir().unwrap();
aristo_in(tmp.path()).arg("init").assert().success();
seed_cluster(
tmp.path(),
"wal_protocol_correctness",
"wal_find_frame_range_invariant",
);
aristo_in(tmp.path())
.args(["canon", "suggestions"])
.assert()
.success()
.stdout(predicates::str::contains("proof-tree suggestions"));
aristo_in(tmp.path())
.args(["canon", "list"])
.assert()
.success()
.stdout(predicates::str::contains("no canon matches"))
.stdout(predicates::str::contains("wal_protocol_correctness").not());
}