use std::io::Write;
fn write_plugin(dir: &std::path::Path) -> std::path::PathBuf {
let plugdir = dir.join(".scc").join("plugins").join("acme.echo");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.echo\"\nname = \"Echo\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"acme.echo\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"echo\": req[\"input\"].get(\"text\", \"\")}}))\n").unwrap();
dir.to_path_buf()
}
#[test]
fn process_plugin_echo_round_trip() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
let mut ap = scc_engine::plugins::active(&root, &scc_indexer::Config::default());
assert_eq!(ap.plugins.len(), 1, "echo plugin discovered");
let out = scc_engine::plugins::call_operation(&mut ap, "acme.echo", serde_json::json!({"text": "hello"})).unwrap();
assert_eq!(out.get("echo").and_then(|v| v.as_str()), Some("hello"));
assert!(out.get("_origin").is_some(), "mandatory provenance {out}");
}
#[test]
fn unknown_operation_is_no_provider() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let mut ap = scc_engine::plugins::active(&root, &scc_indexer::Config::default());
let r = scc_engine::plugins::call_operation(&mut ap, "acme.missing", serde_json::json!({}));
assert!(r.is_err());
}
#[test]
fn lock_changes_cache_key() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
let ap = scc_engine::plugins::active(&root, &scc_indexer::Config::default());
let k1 = scc_engine::plugins::cache_key_fragment(&ap);
assert!(k1.starts_with("plugins:"));
assert_eq!(k1, scc_engine::plugins::cache_key_fragment(&ap));
}
#[test]
fn plugin_config_and_grants_invalidate_cache_key() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
let base_cfg = scc_indexer::Config::default();
let ap0 = scc_engine::plugins::active(&root, &base_cfg);
let k0 = scc_engine::plugins::cache_key_fragment(&ap0);
let mut cfg1 = scc_indexer::Config::default();
cfg1.plugins.config.insert(
"acme.echo".into(),
serde_json::json!({"risk_weight": 0.9}),
);
let ap1 = scc_engine::plugins::active(&root, &cfg1);
let k1 = scc_engine::plugins::cache_key_fragment(&ap1);
assert_ne!(k0, k1, "config change must invalidate the cache key");
let e1 = scc_plugin_host::lock_entry(&ap1.plugins[0]);
assert_eq!(e1.get("config"), Some(&serde_json::json!({"risk_weight": 0.9})), "{e1}");
let mut cfg2 = scc_indexer::Config::default();
cfg2.plugins.grants.insert("acme.echo".into(), vec!["state.read".into()]);
let ap2 = scc_engine::plugins::active(&root, &cfg2);
let k2 = scc_engine::plugins::cache_key_fragment(&ap2);
assert_ne!(k0, k2, "grant change must invalidate the cache key");
let e2 = scc_plugin_host::lock_entry(&ap2.plugins[0]);
assert_eq!(e2.get("grants"), Some(&serde_json::json!(["state.read"])), "{e2}");
let ap0b = scc_engine::plugins::active(&root, &base_cfg);
assert_eq!(k0, scc_engine::plugins::cache_key_fragment(&ap0b));
}
#[test]
fn extension_registration_wires_rank_feature() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def zeta():\n return 1\ndef alpha():\n return 2\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.feat");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.feat\"\nname = \"Feat\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.feature\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"rank-feature:acme.feat\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nsym = req[\"input\"].get(\"symbol\", \"\")\nboost = 1.0 if \"alpha\" in sym else 0.0\nprint(json.dumps({\"output\": {\"score\": boost, \"weight\": 100.0, \"reason\": \"acme-boost\"}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(
&root,
"ranking.symbols",
serde_json::json!({"goal": "zeta", "limit": 10, "explain": true, "include_features": true}),
)
.unwrap();
let items = out["items"].as_array().unwrap();
assert!(!items.is_empty(), "ranked items {out}");
let pos = |sub: &str| items.iter().position(|i| i["id"].as_str().unwrap_or("").contains(sub)).unwrap();
assert!(pos("alpha") < pos("zeta"), "acme-boost moved alpha up: {out}");
assert!(
items[pos("alpha")]["plugin_features"].get("acme.feat.feature").is_some(),
"feature recorded under plugin name: {out}"
);
assert!(
items[pos("alpha")]["reasons"].as_array().unwrap().iter().any(|r| r == "acme-boost"),
"reason recorded: {out}"
);
}
#[test]
fn order_extensions_respects_priority_and_edges() {
use scc_engine::plugins::ExtensionOrder;
let exts = vec![
ExtensionOrder { extension_type: "rank-feature".into(), id: "c".into(), priority: 30, after: vec![], before: vec![] },
ExtensionOrder { extension_type: "rank-feature".into(), id: "a".into(), priority: 10, after: vec![], before: vec![] },
ExtensionOrder { extension_type: "rank-feature".into(), id: "b".into(), priority: 20, after: vec!["rank-feature:a".into()], before: vec![] },
];
let order = scc_engine::plugins::order_extensions(&exts).unwrap();
let ids: Vec<&str> = order.iter().map(|&i| exts[i].id.as_str()).collect();
assert_eq!(ids, vec!["a", "b", "c"], "{ids:?}");
}
#[test]
fn order_extensions_rejects_unknown_and_cycle() {
use scc_engine::plugins::ExtensionOrder;
let unknown = vec![
ExtensionOrder { extension_type: "t".into(), id: "x".into(), priority: 0, after: vec!["t:nope".into()], before: vec![] },
];
assert!(scc_engine::plugins::order_extensions(&unknown).is_err());
let cycle = vec![
ExtensionOrder { extension_type: "t".into(), id: "x".into(), priority: 0, after: vec!["t:y".into()], before: vec![] },
ExtensionOrder { extension_type: "t".into(), id: "y".into(), priority: 0, after: vec!["t:x".into()], before: vec![] },
];
assert!(scc_engine::plugins::order_extensions(&cycle).is_err());
}
#[test]
fn contribution_pipeline_validates_then_commits() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let store = scc_store::Store::open(&dir.path().join("scc.db"), &root).unwrap();
let bad = serde_json::json!({"entities": [], "relationships": [
{"id": "r1", "subject": "ghost", "predicate": "calls", "object": "ghost2", "provenance": "extracted", "confidence": 1.0}
], "evidence": []});
assert!(scc_engine::plugins::commit_contribution(&store, "acme.t", &bad).is_err());
assert!(store.search_entities("ghost", 10).unwrap().is_empty());
let good = serde_json::json!({"entities": [
{"id": "plugin:acme/boundary", "kind": "plugin:acme/security_boundary", "name": "edge", "attributes": {}, "evidence": []}
], "relationships": [], "evidence": []});
let out = scc_engine::plugins::commit_contribution(&store, "acme.t", &good).unwrap();
assert_eq!(out.get("entities"), Some(&serde_json::json!(1)));
let found = store.search_entities("edge", 10).unwrap();
assert!(found.iter().any(|e| e.id == "plugin:acme/boundary"), "{found:?}");
let unscoped = serde_json::json!({"entities": [
{"id": "x", "kind": "custom/thing", "name": "x", "attributes": {}, "evidence": []}
], "relationships": [], "evidence": []});
assert!(scc_engine::plugins::commit_contribution(&store, "acme.t", &unscoped).is_err());
}
#[test]
fn contribution_unknown_keys_fail_loudly() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let store = scc_store::Store::open(&dir.path().join("scc.db"), &root).unwrap();
for key in ["flows", "invariants", "contracts", "typo_key"] {
let batch = serde_json::json!({"entities": [], "relationships": [], "evidence": []});
let mut obj = batch.as_object().cloned().unwrap();
obj.insert(key.into(), serde_json::json!([]));
let err = scc_engine::plugins::commit_contribution(&store, "acme.t", &serde_json::Value::Object(obj));
assert!(err.is_err(), "key '{key}' must be rejected, not dropped: {err:?}");
assert!(err.unwrap_err().to_string().contains(key), "error names the key");
}
let with_diag = serde_json::json!({"entities": [], "relationships": [], "evidence": [],
"diagnostics": [{"level": "warn", "message": "m"}]});
let out = scc_engine::plugins::commit_contribution(&store, "acme.t", &with_diag).unwrap();
assert_eq!(out.get("diagnostics"), Some(&serde_json::json!(1)), "{out}");
}
#[test]
fn contribution_mid_batch_failure_leaves_no_partial_state() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let store = scc_store::Store::open(&dir.path().join("scc.db"), &root).unwrap();
let before = store.stats().unwrap()["entities"];
let mixed = serde_json::json!({"entities": [
{"id": "plugin:acme/ok", "kind": "plugin:acme/thing", "name": "ok", "attributes": {}, "evidence": []},
{"id": "plugin:acme/bad", "kind": "plugin:acme/thing", "name": 42, "attributes": {}, "evidence": []}
], "relationships": [], "evidence": []});
assert!(scc_engine::plugins::commit_contribution(&store, "acme.t", &mixed).is_err());
assert!(store.search_entities("ok", 10).unwrap().is_empty(), "partial entity must roll back");
assert_eq!(store.stats().unwrap()["entities"], before, "entity count unchanged");
}
#[test]
fn features_op_serves_decomposition() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "alpha", "limit": 10})).unwrap();
let feats = out["features"].as_array().unwrap();
assert!(!feats.is_empty(), "{out}");
for f in feats {
for k in ["task_ppr", "global_ppr", "lexical", "semantic",
"confidence", "criticality", "change_risk", "novelty"] {
assert!(f.get(k).and_then(|x| x.as_f64()).is_some(), "missing {k}: {f}");
}
assert!(f.get("plugin_features").is_some(), "{f}");
}
}
#[test]
fn seeds_op_serves_plugin_merge() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(&root, "ranking.seeds",
serde_json::json!({"goal": "alpha"})).unwrap();
assert!(!base["seeds"].as_array().unwrap().is_empty(), "{base}");
let first = base["seeds"][0]["id"].as_str().unwrap().to_string();
let w0 = base["seeds"][0]["weight"].as_f64().unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.seed");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.seed\"\nname = \"Seed\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.seed\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"seed-provider:acme.s\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
std::fs::write(plugdir.join("plugin.py"), format!(
"import json, sys\nprint(json.dumps({{\"output\": {{\"seeds\": [{{\"kind\": \"symbol\", \"id\": \"{first}\", \"weight\": 5.0}}]}}}}))\n")).unwrap();
let out = scc_engine::invoke(&root, "ranking.seeds",
serde_json::json!({"goal": "alpha"})).unwrap();
let hit = out["seeds"].as_array().unwrap().iter()
.find(|x| x["id"] == first).unwrap();
assert!((hit["weight"].as_f64().unwrap() - (w0 + 5.0)).abs() < 1e-9, "{out}");
}
#[test]
fn sidecar_round_trip_stays_out_of_canonical() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let before = scc_engine::invoke(&root, "export.system_ir",
serde_json::json!({"format": "system-ir.json"})).unwrap();
let n_entities = before["entities"].as_array().unwrap().len();
let denied = scc_engine::invoke(&root, "sidecar.put", serde_json::json!({
"plugin": "acme.ghost", "graph": "joern-cpg",
"key": "node/1", "value": {"kind": "METHOD"},
}));
assert!(denied.is_err(), "{denied:?}");
let plugdir = root.join(".scc").join("plugins").join("acme.side");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.side\"\nname = \"Side\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = []\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[permissions]\nstate_read = true\nstate_write = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json\nprint(json.dumps({\"output\": {}}))\n").unwrap();
let ok = scc_engine::invoke(&root, "sidecar.put", serde_json::json!({
"plugin": "acme.side", "graph": "joern-cpg",
"key": "node/1", "value": {"kind": "METHOD", "name": "hello"},
})).unwrap();
assert_eq!(ok["ok"], serde_json::json!(true), "{ok}");
let got = scc_engine::invoke(&root, "sidecar.get", serde_json::json!({
"plugin": "acme.side", "graph": "joern-cpg", "key": "node/1",
})).unwrap();
assert!(got.as_str().unwrap().contains("METHOD"), "{got}");
let scan = scc_engine::invoke(&root, "sidecar.scan", serde_json::json!({
"plugin": "acme.side", "graph": "joern-cpg", "prefix": "node/",
})).unwrap();
assert_eq!(scan["keys"].as_array().unwrap().len(), 1, "{scan}");
let scan2 = scc_engine::invoke(&root, "sidecar.scan", serde_json::json!({
"plugin": "acme.side", "graph": "other", "prefix": "",
})).unwrap();
assert!(scan2["keys"].as_array().unwrap().is_empty(), "{scan2}");
let after = scc_engine::invoke(&root, "export.system_ir",
serde_json::json!({"format": "system-ir.json"})).unwrap();
assert_eq!(after["entities"].as_array().unwrap().len(), n_entities, "sidecar must not leak");
}
#[test]
fn promote_sidecar_enters_canonical_graph() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let store = scc_store::Store::open(&root.join(".scc").join("scc.db"), &root).unwrap();
let ids: Vec<String> = store.all_entities().unwrap().into_iter().map(|e| e.id).collect();
assert!(ids.len() >= 2, "need two endpoints: {ids:?}");
let (a, b) = (ids[0].clone(), ids[1].clone());
let out = scc_engine::invoke(&root, "plugins.promote", serde_json::json!({
"plugin": "acme.joern", "assertions": [
{"subject": a, "predicate": "calls", "object": b,
"confidence": 0.97, "exact": true},
],
})).unwrap();
assert_eq!(out["relationships"], serde_json::json!(1), "{out}");
let rels = store.all_relationships().unwrap();
let hit = rels.iter().find(|r| r.subject == a && r.object == b).unwrap();
assert_eq!(hit.provenance, scc_core::Provenance::Resolved, "{hit:?}");
let bad = scc_engine::invoke(&root, "plugins.promote", serde_json::json!({
"plugin": "acme.joern", "assertions": [
{"subject": a, "predicate": "plugin:acme/reaching_def", "object": b,
"confidence": 0.9, "exact": true},
],
}));
assert!(bad.is_err(), "{bad:?}");
let bad2 = scc_engine::invoke(&root, "plugins.promote", serde_json::json!({
"plugin": "acme.joern", "assertions": [
{"subject": "no-such-id", "predicate": "calls", "object": b,
"confidence": 0.9, "exact": true},
],
}));
assert!(bad2.is_err(), "{bad2:?}");
}
#[test]
fn diversity_policy_plugin_replaces_mmr() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let ranked = |ids: &[&str]| -> Vec<serde_json::Value> {
ids.iter().map(|id| serde_json::json!({
"id": id, "kind": "symbol", "value": 1.0, "token_cost": 10})).collect()
};
let base = scc_engine::invoke(&root, "selection.mmr", serde_json::json!({
"ranked": ranked(&["a", "b", "c"]), "budget": 30,
})).unwrap();
assert_eq!(base["selected"].as_array().unwrap().len(), 3, "{base}");
let plugdir = root.join(".scc").join("plugins").join("acme.d");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.d\"\nname = \"D\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"selection.diversify\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"diversity-policy:acme.top1\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"selected\": [\"b\"]}}))\n").unwrap();
let out = scc_engine::invoke(&root, "selection.mmr", serde_json::json!({
"ranked": ranked(&["a", "b", "c"]), "budget": 30,
})).unwrap();
assert_eq!(out["selected"], serde_json::json!(["b"]), "{out}");
}
#[test]
fn budget_optimizer_plugin_replaces_selection() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let ranked = |ids: &[&str]| -> Vec<serde_json::Value> {
ids.iter().map(|id| serde_json::json!({
"id": id, "kind": "symbol", "value": 1.0, "token_cost": 100})).collect()
};
let base = scc_engine::invoke(&root, "selection.budget", serde_json::json!({
"ranked": ranked(&["a", "b", "c"]), "budget": 300,
})).unwrap();
assert_eq!(base["selected"].as_array().unwrap().len(), 3, "{base}");
let plugdir = root.join(".scc").join("plugins").join("acme.b");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.b\"\nname = \"B\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"selection.optimize\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"budget-optimizer:acme.cheap\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"selected\": [\"c\"]}}))\n").unwrap();
let out = scc_engine::invoke(&root, "selection.budget", serde_json::json!({
"ranked": ranked(&["a", "b", "c"]), "budget": 300,
})).unwrap();
assert_eq!(out["selected"], serde_json::json!(["c"]), "{out}");
}
#[test]
fn quota_policy_plugin_overrides_fractions() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let ranked = |ids: &[&str]| -> Vec<serde_json::Value> {
ids.iter().map(|id| serde_json::json!({
"id": id, "kind": "symbol", "value": 1.0, "token_cost": 100})).collect()
};
let base = scc_engine::invoke(&root, "selection.quotas", serde_json::json!({
"ranked": ranked(&["a", "b", "c"]),
"quotas": [{"kind": "symbol", "fraction": 0.5}],
"budget": 300,
})).unwrap();
assert!(base.get("quota_overrides").is_none(), "{base}");
assert_eq!(base["selected"].as_array().unwrap().len(), 1, "{base}");
let plugdir = root.join(".scc").join("plugins").join("acme.q");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.q\"\nname = \"Q\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"selection.quotas\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"quota-policy:acme.lenient\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"quotas\": [{\"kind\": \"symbol\", \"fraction\": 1.0}]}}))\n").unwrap();
let out = scc_engine::invoke(&root, "selection.quotas", serde_json::json!({
"ranked": ranked(&["a", "b", "c"]),
"quotas": [{"kind": "symbol", "fraction": 0.5}],
"budget": 300,
})).unwrap();
assert_eq!(out["selected"].as_array().unwrap().len(), 3, "{out}");
assert_eq!(out["quota_overrides"], serde_json::json!([{"kind": "symbol", "fraction": 1.0}]), "{out}");
}
#[test]
fn pipeline_fragment_rekeys_rank_cache() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
let cfg = scc_indexer::Config::default();
scc_engine::index::full(&root, &cfg).unwrap();
let store = scc_store::Store::open(&dir.path().join("scc.db"), &root).unwrap();
let graph = scc_graph::RealityGraph::load(&store).unwrap();
let settings = scc_context::ContextSettings::default();
let stale: Vec<String> = Vec::new();
let comp = scc_context::ContextCompiler::new(&store, &graph, settings, stale);
let k0 = scc_engine::plugins::cache_key_fragment(
&scc_engine::plugins::active(&root, &cfg));
let plugdir = root.join(".scc").join("plugins").join("acme.pipe");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.pipe\"\nname = \"Pipe\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = []\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let k1 = scc_engine::plugins::cache_key_fragment(
&scc_engine::plugins::active(&root, &cfg));
assert_ne!(k0, k1, "install must change the pipeline fragment");
let epoch = comp.store.cache_epoch().unwrap();
let entry = scc_context::startup::GlobalRankCache {
epoch: epoch.clone(), policy: scc_context::startup::trust_policy_str(comp.view.policy()),
salt: comp.settings.rank_salt.clone(),
global_vector: vec![1.0], node_symbol_map: Default::default(),
candidates_epoch: epoch, candidate_ids: vec![],
hits: 0,
};
scc_context::startup::store_global_rank_cache_with_pipeline(&comp, &entry, &k0);
assert!(scc_context::startup::load_global_rank_cache_with_pipeline(&comp, &k0).is_some());
assert!(scc_context::startup::load_global_rank_cache_with_pipeline(&comp, &k1).is_none(),
"other pipeline must miss");
assert!(scc_context::startup::load_global_rank_cache(&comp).is_none(),
"legacy empty pipeline must miss a pipelined entry");
}
#[test]
fn viewer_panel_plugin_returns_structured_data() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.pan");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.pan\"\nname = \"Pan\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"viewer.panel\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"viewer-panel:acme.taint\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"title\": \"Taint\", \"html\": \"<p>tainted</p>\"}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(&root, "viewer.panels", serde_json::json!({})).unwrap();
let panels = out["panels"].as_array().unwrap();
assert_eq!(panels.len(), 1, "{out}");
assert_eq!(panels[0]["id"], serde_json::json!("acme.taint"), "{out}");
assert_eq!(panels[0]["plugin"], serde_json::json!("acme.pan"), "{out}");
assert!(panels[0]["html"].as_str().unwrap().contains("tainted"), "{out}");
}
#[test]
fn exporter_plugin_renders_unknown_format() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.exp");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.exp\"\nname = \"Exp\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"export.render\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"exporter:acme.sarif\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"format-available\": True, \"text\": \"SARIF-OK\"}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(&root, "export.system_ir", serde_json::json!({"format": "acme.sarif"})).unwrap();
assert_eq!(out["output"], serde_json::json!("SARIF-OK"), "{out}");
assert_eq!(out["plugin"], serde_json::json!("acme.exp"), "{out}");
let native = scc_engine::invoke(&root, "export.system_ir", serde_json::json!({"format": "system-ir.json"})).unwrap();
assert!(native.get("entities").is_some(), "{native}");
}
#[test]
fn verify_diagnostic_plugin_appends_provenance_section() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.ver");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.ver\"\nname = \"Ver\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"verify.diagnostic\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"verify-diagnostic:acme.stale\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"diagnostic\": \"stale: x\"}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(&root, "context.verify", serde_json::json!({})).unwrap();
let content = out["content"].as_str().unwrap_or("");
assert!(content.contains("# PLUGIN VERIFY DIAGNOSTIC acme.stale (from acme.ver"), "{content}");
assert!(content.contains("stale: x"), "{content}");
}
#[test]
fn startup_section_plugin_appends_provenance_section() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.boot");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.boot\"\nname = \"Boot\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"startup.section\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"startup-section:acme.banner\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nprint(json.dumps({\"output\": {\"section\": \"banner: hi\"}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(&root, "context.startup", serde_json::json!({})).unwrap();
let text = out["text"].as_str().unwrap_or("");
assert!(text.contains("# PLUGIN STARTUP SECTION acme.banner (from acme.boot"), "{text}");
assert!(text.contains("banner: hi"), "{text}");
}
#[test]
fn context_section_plugin_appends_provenance_section() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.sec");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.sec\"\nname = \"Sec\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"context.section\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"context-section:acme.impact\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\ngoal = req[\"input\"].get(\"goal\", \"\")\nprint(json.dumps({\"output\": {\"section\": \"risk: \" + goal}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(
&root,
"context.task",
serde_json::json!({"goal": "hello", "files": [], "symbols": [], "budget": null, "hook": false}),
)
.unwrap();
let content = out["pack"]["content"].as_str().unwrap_or("");
assert!(content.contains("# PLUGIN SECTION acme.impact (from acme.sec"), "{content}");
assert!(content.contains("risk: hello"), "{content}");
}
#[test]
fn plugin_lockfile_round_trip_and_drift() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
let ap = scc_engine::plugins::active(&root, &scc_indexer::Config::default());
assert!(scc_plugin_host::check_lockfile(&root, &ap.plugins).is_ok());
scc_plugin_host::write_lockfile(&root, &ap.plugins).unwrap();
assert!(root.join(".scc").join("plugins.lock").is_file());
let ap2 = scc_engine::plugins::active(&root, &scc_indexer::Config::default());
assert!(scc_plugin_host::check_lockfile(&root, &ap2.plugins).is_ok());
let manifest = root.join(".scc").join("plugins").join("acme.echo").join("scc-plugin.toml");
let text = std::fs::read_to_string(&manifest).unwrap().replace("1.0.0", "9.9.9");
std::fs::write(&manifest, text).unwrap();
let ap3 = scc_engine::plugins::active(&root, &scc_indexer::Config::default());
let err = scc_plugin_host::check_lockfile(&root, &ap3.plugins).unwrap_err();
assert!(err.contains("acme.echo"), "{err}");
}
#[test]
fn plugin_lock_and_check_ops_round_trip() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
let out = scc_engine::invoke(&root, "plugins.lock", serde_json::json!({})).unwrap();
assert_eq!(out.get("ok"), Some(&serde_json::json!(true)), "{out}");
let check = scc_engine::invoke(&root, "plugins.check", serde_json::json!({})).unwrap();
assert_eq!(check.get("ok"), Some(&serde_json::json!(true)), "{check}");
}
#[test]
fn plugin_inspect_aliases_describe() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
for op in ["plugins.describe", "plugins.inspect"] {
let v = scc_engine::invoke(&root, op, serde_json::json!({"id": "acme.echo"})).unwrap();
assert_eq!(v["manifest"]["id"], serde_json::json!("acme.echo"), "{op}: {v}");
}
}
#[test]
fn plugin_enable_disable_round_trip() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
std::fs::write(root.join(".scc").join("config.yaml"), "schema: 1\ncontext:\n startup_tokens: 4242\n").unwrap();
let en = scc_engine::invoke(&root, "plugins.enable", serde_json::json!({"id": "acme.echo"})).unwrap();
assert_eq!(en["ok"], serde_json::json!(true), "{en}");
assert!(en["enabled"].as_array().unwrap().iter().any(|x| x == "acme.echo"), "{en}");
let text = std::fs::read_to_string(root.join(".scc").join("config.yaml")).unwrap();
assert!(text.contains("startup_tokens: 4242"), "other keys survive: {text}");
let e = scc_engine::invoke(&root, "plugins.enable", serde_json::json!({"id": "no.such"}));
assert!(e.is_err(), "typo must fail: {e:?}");
let dis = scc_engine::invoke(&root, "plugins.disable", serde_json::json!({"id": "acme.echo"})).unwrap();
assert_eq!(dis["ok"], serde_json::json!(true), "{dis}");
assert!(!dis["enabled"].as_array().unwrap().iter().any(|x| x == "acme.echo"), "{dis}");
}
#[test]
fn edge_weight_contributor_alters_rank() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.edge");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.edge\"\nname = \"Edge\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.edge_weight\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"edge-weight:acme.edge\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nobj = req[\"input\"].get(\"object\", \"\")\nmode = \"multiply\" if \"alpha\" in obj else \"none\"\nprint(json.dumps({\"output\": {\"mode\": mode, \"value\": 0.001}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(
&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10}),
)
.unwrap();
let items = base["items"].as_array().unwrap();
let pos = |sub: &str| items.iter().position(|i| i["id"].as_str().unwrap_or("").contains(sub)).unwrap();
let base_alpha = pos("alpha");
assert!(
items.iter().all(|i| i["reasons"].as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("edge-weights("))),
"edge-weight reasons recorded: {base}"
);
assert!(
base["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap_or("").contains("edge-weight")),
"edge-weight warning recorded: {base}"
);
assert!(base_alpha < items.len(), "alpha present: {base}");
}
#[test]
fn plugin_state_crud_is_namespaced_and_gated() {
let dir = tempfile::TempDir::new().unwrap();
let root = write_plugin(dir.path());
let denied = scc_engine::invoke(
&root, "plugin_state.get",
serde_json::json!({"plugin": "acme.echo", "key": "k"}),
);
assert!(denied.is_err(), "state without grant must fail: {denied:?}");
std::fs::create_dir_all(root.join(".scc")).unwrap();
std::fs::write(
root.join(".scc").join("config.yaml"),
"schema: 1\nplugins:\n grants:\n acme.echo: [state.read, state.write]\n",
)
.unwrap();
let put = scc_engine::invoke(
&root, "plugin_state.put",
serde_json::json!({"plugin": "acme.echo", "key": "cursor", "value": {"n": 1}}),
)
.unwrap();
assert_eq!(put.get("ok"), Some(&serde_json::json!(true)), "{put}");
let got = scc_engine::invoke(
&root, "plugin_state.get",
serde_json::json!({"plugin": "acme.echo", "key": "cursor"}),
)
.unwrap();
assert!(got.as_str().is_some_and(|s| s.contains('1')), "{got}");
let other = scc_engine::invoke(
&root, "plugin_state.get",
serde_json::json!({"plugin": "acme.other", "key": "cursor"}),
);
assert!(other.is_err(), "unknown plugin must fail: {other:?}");
let scan = scc_engine::invoke(
&root, "plugin_state.scan",
serde_json::json!({"plugin": "acme.echo", "prefix": "cur", "limit": 10}),
)
.unwrap();
assert_eq!(scan["keys"].as_array().map(|a| a.len()), Some(1), "{scan}");
let del = scc_engine::invoke(
&root, "plugin_state.delete",
serde_json::json!({"plugin": "acme.echo", "key": "cursor"}),
)
.unwrap();
assert_eq!(del.get("ok"), Some(&serde_json::json!(true)), "{del}");
let gone = scc_engine::invoke(
&root, "plugin_state.get",
serde_json::json!({"plugin": "acme.echo", "key": "cursor"}),
)
.unwrap();
assert!(gone.is_null(), "deleted key reads null: {gone}");
}
#[test]
fn pagerank_stage_ops_ignore_edge_weights() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let score_of = |v: &serde_json::Value, sub: &str| -> f64 {
v["vector"].as_array().unwrap().iter()
.find(|e| e["id"].as_str().unwrap_or("").contains(sub))
.unwrap_or_else(|| panic!("{sub} missing: {v}"))["score"].as_f64().unwrap()
};
let plain_task = scc_engine::invoke(&root, "ranking.pagerank.task", serde_json::json!({"goal": "alpha"})).unwrap();
let plain_global = scc_engine::invoke(&root, "ranking.pagerank.global", serde_json::json!({})).unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.edge");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.edge\"\nname = \"Edge\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.edge_weight\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"edge-weight:acme.edge\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nobj = req[\"input\"].get(\"object\", \"\")\nmode = \"multiply\" if \"alpha\" in obj else \"none\"\nprint(json.dumps({\"output\": {\"mode\": mode, \"value\": 0.001}}))\n").unwrap();
let hooked_task = scc_engine::invoke(&root, "ranking.pagerank.task", serde_json::json!({"goal": "alpha"})).unwrap();
let hooked_global = scc_engine::invoke(&root, "ranking.pagerank.global", serde_json::json!({})).unwrap();
for (label, plain, hooked) in [("task", &plain_task, &hooked_task), ("global", &plain_global, &hooked_global)] {
for (pe, he) in plain["vector"].as_array().unwrap().iter().zip(hooked["vector"].as_array().unwrap()) {
let (ps, hs) = (pe["score"].as_f64().unwrap(), he["score"].as_f64().unwrap());
assert!((ps - hs).abs() < 1e-9, "raw {label} vector must ignore edge-weight hooks: {} {ps} vs {hs}", pe["id"]);
}
}
let _ = score_of(&plain_task, "alpha");
}
#[test]
fn blend_profile_plugin_rescales_rank() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.prof");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.prof\"\nname = \"Prof\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.profile\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"blend-profile:change-risk\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json\nprint(json.dumps({\"output\": {\"weights\": {\"task_ppr\": 0, \"global_ppr\": 0, \"lexical\": 0, \"semantic\": 0, \"confidence\": 0, \"criticality\": 0, \"change_risk\": 1, \"novelty\": 0}}}))\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let out = scc_engine::invoke(
&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10, "profile": "change-risk"}),
)
.unwrap();
let items = out["items"].as_array().unwrap();
assert!(!items.is_empty(), "profile rank must return items: {out}");
assert!(items.iter().all(|i| i["rank"].as_f64().unwrap() == 0.0), "zeroed profile must zero ranks: {out}");
assert!(items.iter().all(|i| i["reasons"].as_array().unwrap().iter().any(|r| r == "profile:change-risk")), "profile recorded: {out}");
let err = scc_engine::invoke(
&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10, "profile": "nope"}),
);
assert!(err.is_err(), "unknown profile must fail: {err:?}");
}
#[test]
fn mmr_similarity_hook_diversifies() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let ranked = serde_json::json!({"ranked": [
{"id": "a1", "value": 0.9, "group": "g1"},
{"id": "a2", "value": 0.8, "group": "g1"},
{"id": "b1", "value": 0.7, "group": "g2"}
], "budget": 3, "lambda": 0.0});
let out = scc_engine::invoke(&root, "selection.mmr", ranked).unwrap();
let sel = out["selected"].as_array().unwrap();
let ids: Vec<&str> = sel.iter().map(|v| v.as_str().unwrap()).collect();
assert_eq!(ids[0], "a1", "highest value first: {ids:?}");
assert_eq!(ids[1], "b1", "diversity picks the other group second: {ids:?}");
assert_eq!(scc_engine::ranking::default_similarity(Some("x"), Some("x")), 1.0);
assert_eq!(scc_engine::ranking::default_similarity(Some("x"), Some("y")), 0.0);
assert_eq!(scc_engine::ranking::default_similarity(None, Some("x")), 0.0);
assert_eq!(scc_engine::ranking::default_similarity(Some(""), Some("")), 0.0);
let plug: scc_engine::ranking::SimilarityFn =
std::sync::Arc::new(|_a, _b, _ga, _gb| 0.42);
assert!((scc_engine::ranking::fold_similarity(&[plug], "a", "b", None, None) - 0.42).abs() < 1e-12);
assert!((scc_engine::ranking::fold_similarity(&[], "a", "b", Some("g"), Some("g")) - 1.0).abs() < 1e-12);
}
#[test]
fn unknown_grant_names_surface_diagnostics() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def hello():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let mut cfg = scc_indexer::Config::default();
cfg.plugins.grants.insert(
"any.plugin".into(),
vec!["state.read".into(), "graph.write".into(), "repo_read".into()],
);
let ap = scc_engine::plugins::active(&root, &cfg);
assert_eq!(ap.diagnostics.len(), 2, "both typos diagnosed: {:?}", ap.diagnostics);
assert!(ap.diagnostics.iter().all(|d| d.plugin == "any.plugin"), "{:?}", ap.diagnostics);
assert!(ap.diagnostics.iter().any(|d| d.error.contains("graph.write")), "{:?}", ap.diagnostics);
assert!(scc_plugin_api::Permission::parse("evidence.contribute").is_ok());
assert!(scc_plugin_api::Permission::parse("graph.contribute").is_ok());
std::fs::create_dir_all(root.join(".scc")).unwrap();
std::fs::write(
root.join(".scc").join("config.yaml"),
"schema: 1\nplugins:\n grants:\n any.plugin: [state.read, graph.write, repo_read]\n",
)
.unwrap();
let doc = scc_engine::invoke(&root, "plugins.doctor", serde_json::json!({})).unwrap();
let diags = doc["diagnostics"].as_array().unwrap();
assert!(diags.iter().any(|d| d["error"].as_str().unwrap_or("").contains("graph.write")), "{doc}");
}
#[test]
fn candidate_provider_merges_by_id() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(
&root, "ranking.candidates",
serde_json::json!({"goal": "zzz-no-match", "limit": 50}),
)
.unwrap();
let base_ids: Vec<String> = base["candidates"].as_array().unwrap().iter()
.map(|c| c["id"].as_str().unwrap().to_string()).collect();
let plugdir = root.join(".scc").join("plugins").join("acme.cand");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.cand\"\nname = \"Cand\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.candidates\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"candidate-provider:acme.cand\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
let overlap = base_ids.first().cloned().unwrap_or_else(|| "repo://repo/symbol/main.py/alpha".into());
let body = format!(
"import json\nprint(json.dumps({{\"output\": {{\"candidates\": [{{\"id\": \"plugin:acme/novel\", \"kind\": \"symbol\", \"name\": \"novel\", \"score\": 99.0}}, {{\"id\": \"{overlap}\", \"kind\": \"symbol\", \"name\": \"x\", \"score\": 99.0}}, {{\"id\": \"\", \"kind\": \"symbol\", \"name\": \"empty\", \"score\": 99.0}}]}}}}))\n"
);
f.write_all(body.as_bytes()).unwrap();
let hooked = scc_engine::invoke(
&root, "ranking.candidates",
serde_json::json!({"goal": "zzz-no-match", "limit": 50}),
)
.unwrap();
let cands = hooked["candidates"].as_array().unwrap();
assert!(cands.iter().any(|c| c["id"] == "plugin:acme/novel"), "novel id merged: {hooked}");
let novel = cands.iter().find(|c| c["id"] == "plugin:acme/novel").unwrap();
assert_eq!(novel["reason"], serde_json::json!("plugin:acme.cand"), "provider provenance: {hooked}");
let over = cands.iter().find(|c| c["id"].as_str() == Some(overlap.as_str())).unwrap();
assert_eq!(over["score"].as_f64().unwrap(), 99.0, "max score wins: {hooked}");
assert!(cands.iter().all(|c| !c["id"].as_str().unwrap_or("").is_empty()), "empty ids skipped");
let scores: Vec<f64> = cands.iter().map(|c| c["score"].as_f64().unwrap()).collect();
assert!(scores.windows(2).all(|w| w[0] >= w[1]), "sorted desc: {scores:?}");
}
#[test]
fn evidence_provider_plugin_commits_batch() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let plugdir = root.join(".scc").join("plugins").join("acme.ev");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.ev\"\nname = \"Ev\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"evidence.import\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"evidence-provider:acme.ev\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
)
.unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json\nprint(json.dumps({\"output\": {\"batch\": {\"entities\": [{\"id\": \"plugin:acme.ev/finding/1\", \"kind\": \"plugin:acme.ev/finding\", \"name\": \"finding-1\"}], \"relationships\": [], \"evidence\": [{\"id\": \"evidence:acme-ev-1\", \"type\": \"source\"}], \"diagnostics\": []}}}))\n").unwrap();
let out = scc_engine::invoke(&root, "import.acme.ev", serde_json::json!({"file": "main.py"})).unwrap();
assert_eq!(out.get("symbols").and_then(|v| v.as_u64()), Some(1), "one entity committed: {out}");
assert_eq!(out.get("imports").and_then(|v| v.as_u64()), Some(1), "one evidence committed: {out}");
let err = scc_engine::invoke(&root, "import.acme.ghost", serde_json::json!({"file": "main.py"}));
assert!(err.is_err(), "unknown plugin must fail: {err:?}");
assert!(err.unwrap_err().to_string().contains("unknown import format"), "import vocabulary");
}
#[test]
fn rank_edge_provider_adds_diffusion_without_canonical_facts() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let score_of = |v: &serde_json::Value, sub: &str| -> f64 {
v["items"].as_array().unwrap().iter()
.find(|i| i["id"].as_str().unwrap_or("").contains(sub))
.unwrap_or_else(|| panic!("{sub} missing: {v}"))["rank"].as_f64().unwrap()
};
let rel_count = scc_engine::invoke(&root, "graph.relationships", serde_json::json!({})).unwrap();
let n_rels = rel_count.as_array().unwrap().len();
let base = scc_engine::invoke(&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert!(base.get("warnings").and_then(|v| v.as_array()).map(|w| w.is_empty()).unwrap_or(true), "no edge warnings yet: {base}");
let edges = scc_engine::invoke(&root, "ranking.edges", serde_json::json!({})).unwrap();
let ids: Vec<String> = edges["edges"].as_array().unwrap().iter()
.flat_map(|e| [e["subject"].as_str().unwrap_or(""), e["object"].as_str().unwrap_or("")])
.map(str::to_string).collect();
let has = |sub: &str| ids.iter().find(|i| i.contains(sub)).cloned().unwrap();
let (zeta, alpha) = (has("zeta"), has("alpha"));
let plugdir = root.join(".scc").join("plugins").join("acme.redge");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.redge\"\nname = \"Redge\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.rank_edges\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"rank-edge:acme.redge\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
let body = format!(
"import json\nprint(json.dumps({{\"output\": {{\"edges\": [{{\"subject\": \"{zeta}\", \"predicate\": \"calls\", \"object\": \"{alpha}\", \"weight\": 50.0}}, {{\"subject\": \"repo://nowhere/x\", \"predicate\": \"calls\", \"object\": \"repo://nowhere/y\", \"weight\": 99.0}}]}}}}))\n"
);
f.write_all(body.as_bytes()).unwrap();
let out = scc_engine::invoke(&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert!(
out["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap_or("").contains("rank-time edge")),
"rank-edge warning recorded: {out}"
);
assert!(
out["items"].as_array().unwrap().iter().all(|i| i["reasons"].as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("rank-edges("))),
"rank-edge reasons recorded: {out}"
);
assert!(
(score_of(&out, "alpha") - score_of(&base, "alpha")).abs() > 1e-9,
"extra edge moved alpha's score"
);
let after = scc_engine::invoke(&root, "graph.relationships", serde_json::json!({})).unwrap();
assert_eq!(after.as_array().unwrap().len(), n_rels, "rank edges never canonical");
}
#[test]
fn novelty_and_criticality_providers_override_blend() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let feat_of = |v: &serde_json::Value, sub: &str| -> serde_json::Value {
v["features"].as_array().unwrap().iter()
.find(|f| f["id"].as_str().unwrap_or("").contains(sub)).unwrap().clone()
};
let base = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert_eq!(feat_of(&base, "alpha")["novelty"].as_f64().unwrap(), 1.0, "default novelty 1.0: {base}");
for (pid, ext, op, key) in [
("acme.crit", "criticality-provider:acme.c", "ranking.criticality", "criticality"),
("acme.nov", "novelty-provider:acme.n", "ranking.novelty", "novelty"),
("acme.bad", "novelty-provider:acme.b", "ranking.novelty", "novelty"),
] {
let plugdir = root.join(".scc").join("plugins").join(pid);
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
format!("[plugin]\nid = \"{pid}\"\nname = \"P\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"{op}\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"{ext}\" = {{priority=1}}\n\n[permissions]\nrepo_read = true\n"),
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
let val = if pid == "acme.bad" { "99.0" } else { "0.0" };
let body = format!("import json\nprint(json.dumps({{\"output\": {{\"{key}\": {val}}}}}))\n");
f.write_all(body.as_bytes()).unwrap();
}
let out = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
let alpha = feat_of(&out, "alpha");
assert_eq!(alpha["criticality"].as_f64().unwrap(), 0.0, "criticality overridden: {out}");
assert_eq!(alpha["novelty"].as_f64().unwrap(), 0.0, "novelty overridden, bad value abstained: {out}");
let items = scc_engine::invoke(&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert!(
items["items"].as_array().unwrap().iter().all(|i|
i["reasons"].as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("criticality:provider"))
&& i["reasons"].as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("novelty:provider"))),
"override sources recorded: {items}"
);
}
#[test]
fn risk_provider_overrides_change_risk() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert!(
base["features"].as_array().unwrap().iter().all(|f| f["change_risk"].as_f64().unwrap() == 0.0),
"fresh tree has no risk: {base}"
);
let plugdir = root.join(".scc").join("plugins").join("acme.risk");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.risk\"\nname = \"R\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.risk\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"risk-provider:acme.r\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nsym = req[\"input\"].get(\"symbol\", \"\")\nval = 1.0 if \"alpha\" in sym else None\nout = {\"risk\": val} if val is not None else {}\nprint(json.dumps({\"output\": out}))\n").unwrap();
let out = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
let alpha = out["features"].as_array().unwrap().iter()
.find(|f| f["id"].as_str().unwrap_or("").contains("alpha")).unwrap();
let zeta = out["features"].as_array().unwrap().iter()
.find(|f| f["id"].as_str().unwrap_or("").contains("zeta")).unwrap();
assert_eq!(alpha["change_risk"].as_f64().unwrap(), 1.0, "alpha risk overridden: {out}");
assert_eq!(zeta["change_risk"].as_f64().unwrap(), 0.0, "zeta abstains to default: {out}");
let items = scc_engine::invoke(&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert!(
items["items"].as_array().unwrap().iter()
.find(|i| i["id"].as_str().unwrap_or("").contains("alpha")).unwrap()["reasons"]
.as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("risk:provider")),
"risk source recorded: {items}"
);
}
#[test]
fn semantic_provider_feeds_blend_slot() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\ndef zeta():\n return alpha()\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "alpha", "limit": 10})).unwrap();
assert!(
base["features"].as_array().unwrap().iter().all(|f| f["semantic"].as_f64().unwrap() == 0.0),
"no scorer, no semantic: {base}"
);
let plugdir = root.join(".scc").join("plugins").join("acme.sem");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.sem\"\nname = \"S\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.semantic\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"semantic-provider:acme.s\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json, sys\nreq = json.load(sys.stdin)\nsym = req[\"input\"].get(\"symbol\", \"\")\nval = 1.0 if \"alpha\" in sym else None\nout = {\"semantic\": val} if val is not None else {}\nprint(json.dumps({\"output\": out}))\n").unwrap();
let out = scc_engine::invoke(&root, "ranking.features",
serde_json::json!({"goal": "alpha", "limit": 10})).unwrap();
let alpha = out["features"].as_array().unwrap().iter()
.find(|f| f["id"].as_str().unwrap_or("").contains("alpha")).unwrap();
let zeta = out["features"].as_array().unwrap().iter()
.find(|f| f["id"].as_str().unwrap_or("").contains("zeta")).unwrap();
assert_eq!(alpha["semantic"].as_f64().unwrap(), 1.0, "alpha semantic fed: {out}");
assert_eq!(zeta["semantic"].as_f64().unwrap(), 0.0, "zeta abstains to default: {out}");
let items = scc_engine::invoke(&root, "ranking.symbols",
serde_json::json!({"goal": "alpha", "limit": 10})).unwrap();
assert!(
items["items"].as_array().unwrap().iter()
.find(|i| i["id"].as_str().unwrap_or("").contains("alpha")).unwrap()["reasons"]
.as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("semantic:provider")),
"semantic source recorded: {items}"
);
}
#[test]
fn runtime_evidence_plugin_edges_land_in_status() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(&root, "runtime.status", serde_json::json!({})).unwrap();
assert!(base.as_array().unwrap().is_empty(), "no edges yet: {base}");
for (pid, ext, body) in [
("acme.rt", "runtime-evidence:acme.r",
"import json, sys\nprint(json.dumps({\"output\": {\"edges\": [{\"source\": \"web\", \"target\": \"api\", \"count\": 3}]}}))\n"),
("acme.dead", "runtime-evidence:acme.d", "import sys\nsys.exit(7)\n"),
] {
let plugdir = root.join(".scc").join("plugins").join(pid);
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
format!("[plugin]\nid = \"{pid}\"\nname = \"P\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"runtime.evidence\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"{ext}\" = {{priority=1}}\n\n[permissions]\nrepo_read = true\n"),
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(body.as_bytes()).unwrap();
}
let out = scc_engine::invoke(&root, "runtime.ingest", serde_json::json!({"body": "[]"})).unwrap();
assert_eq!(out["status"], serde_json::json!("accepted"), "{out}");
let st = scc_engine::invoke(&root, "runtime.status", serde_json::json!({})).unwrap();
let hit = st.as_array().unwrap().iter()
.find(|e| e["source"] == "web" && e["target"] == "api").unwrap();
assert_eq!(hit["count"].as_u64().unwrap(), 3, "plugin edge landed: {st}");
}
#[test]
fn component_signal_plugin_nominates_component() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::create_dir_all(root.join("acme")).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\n").unwrap();
std::fs::write(root.join("acme").join("widget.py"), "def widget():\n return 3\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(&root, "graph.entities", serde_json::json!({})).unwrap();
assert!(
base.as_array().unwrap().iter().all(|e| e["name"] != "acme-widget"),
"no widget component before the plugin: {base}"
);
let plugdir = root.join(".scc").join("plugins").join("acme.comp");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.comp\"\nname = \"Comp\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"components.signals\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"component-signal:acme.c\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json\nprint(json.dumps({\"output\": {\"signals\": [{\"name\": \"acme-widget\", \"dirs\": [\"acme\"]}, {\"name\": \"\", \"dirs\": []}]}}))\n").unwrap();
scc_engine::invoke(&root, "graph.recompile", serde_json::json!({})).unwrap();
let after = scc_engine::invoke(&root, "graph.entities", serde_json::json!({})).unwrap();
let widget = after.as_array().unwrap().iter()
.find(|e| e["name"] == "acme-widget")
.unwrap_or_else(|| panic!("plugin component landed: {after}"));
assert_eq!(widget["attributes"]["boundary_kind"], serde_json::json!("plugin"), "{widget}");
}
#[test]
fn rank_node_plugin_extends_universe_without_canonical_facts() {
use std::io::Write;
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("main.py"), "def alpha():\n return 1\n").unwrap();
scc_engine::index::full(&root, &scc_indexer::Config::default()).unwrap();
let base = scc_engine::invoke(&root, "ranking.universe", serde_json::json!({})).unwrap();
let n_base = base["nodes"].as_array().unwrap().len();
let n_entities = scc_engine::invoke(&root, "graph.entities", serde_json::json!({})).unwrap();
let n_ents = n_entities.as_array().unwrap().len();
let plugdir = root.join(".scc").join("plugins").join("acme.rnode");
std::fs::create_dir_all(&plugdir).unwrap();
std::fs::write(
plugdir.join("scc-plugin.toml"),
"[plugin]\nid = \"acme.rnode\"\nname = \"Rnode\"\nversion = \"1.0.0\"\napi = \"1\"\noperations = [\"ranking.rank_nodes\"]\n\n[runtime]\ncommand = [\"python3\", \"plugin.py\"]\n\n[extensions]\n\"rank-node:acme.rnode\" = {priority=1}\n\n[permissions]\nrepo_read = true\n",
).unwrap();
let mut f = std::fs::File::create(plugdir.join("plugin.py")).unwrap();
f.write_all(b"import json\nprint(json.dumps({\"output\": {\"nodes\": [{\"id\": \"plugin://acme/hotspot\", \"kind\": \"symbol\"}, {\"id\": \"plugin://acme/weird\", \"kind\": \"nonsense\"}, {\"id\": \"\", \"kind\": \"symbol\"}]}}))\n").unwrap();
let out = scc_engine::invoke(&root, "ranking.universe", serde_json::json!({})).unwrap();
let ids: Vec<&str> = out["nodes"].as_array().unwrap().iter()
.map(|n| n["id"].as_str().unwrap_or("")).collect();
assert_eq!(ids.len(), n_base + 1, "exactly one node admitted: {out}");
assert!(ids.contains(&"plugin://acme/hotspot"), "{out}");
let syms = scc_engine::invoke(&root, "ranking.symbols",
serde_json::json!({"goal": "", "limit": 10})).unwrap();
assert!(
syms["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap_or("").contains("rank-universe node")),
"node warning recorded: {syms}"
);
assert!(
syms["items"].as_array().unwrap().iter().all(|i| i["reasons"].as_array().unwrap().iter().any(|r| r.as_str().unwrap_or("").starts_with("rank-nodes("))),
"node reasons recorded: {syms}"
);
let after = scc_engine::invoke(&root, "graph.entities", serde_json::json!({})).unwrap();
assert_eq!(after.as_array().unwrap().len(), n_ents, "rank nodes never canonical");
}