Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

src/code_room/reader/wired/tests.rs

//! Every surface twice: a real answer from the `shop` room with its known
//! values, and the honest state when nothing is consumed — never a silent
//! empty.

use serde_json::{Value, json};

use super::super::fixture::{self, shop::*};
use super::*;
use crate::code_room::{Reach, State};

fn shop() -> Reach<'static> {
    Reach::room_only(&fixture::shop().handle)
}

fn ask(surface: &str, params: Value) -> Value {
    answer(surface, &shop(), &params).unwrap_or_else(|r| panic!("{surface}: refused [{}] {}", r.state, r.note))
}

fn refused(surface: &str, reach: &Reach<'_>, params: Value) -> Refusal {
    match answer(surface, reach, &params) {
        Err(r) => r,
        Ok(v) => panic!("{surface}: expected a refusal, got {v}"),
    }
}

fn strs(v: &Value) -> Vec<String> {
    v.as_array().unwrap_or_else(|| panic!("not an array: {v}")).iter().map(|x| x.as_str().unwrap_or_else(|| panic!("not a string: {x}")).to_string()).collect()
}

fn col(rows: &Value, key: &str) -> Vec<String> {
    let mut out: Vec<String> = rows.as_array().unwrap_or_else(|| panic!("not rows: {rows}")).iter().map(|r| r[key].as_str().unwrap_or("").to_string()).collect();
    out.sort();
    out
}

fn s(v: &[&str]) -> Vec<String> {
    v.iter().map(|x| x.to_string()).collect()
}

fn missing(v: &Value) -> Vec<String> {
    v["evidence"]["missing"].as_array().map(|a| a.iter().map(|m| m["input"].as_str().unwrap_or("").to_string()).collect()).unwrap_or_default()
}

fn notes(v: &Value) -> String {
    v["evidence"]["notes"].as_array().map(|a| a.iter().map(|n| n.as_str().unwrap_or("")).collect::<Vec<_>>().join(" | ")).unwrap_or_default()
}

// ------------------------------------------------------------- the first proof

/// `Mimir.RepoOverview`'s knowledge block is the room's own account of the repo.
#[test]
fn the_knowledge_block_is_what_the_room_holds() {
    let v = knowledge_block(&shop(), SHOP).unwrap();
    assert_eq!(v["source"], "code_room");
    assert_eq!(v["consumed"][0]["repo"], SHOP);
    assert_eq!(v["consumed"][0]["seq"], 2);
    assert!(v["consumed"][0]["sha"].as_str().is_some_and(|s| s.len() >= 7), "{v}");
    assert_eq!(v["symbols"], 15, "8 fn + 2 method + 3 mod + 1 struct + 1 impl");
    assert_eq!(v["symbols_by_kind"], json!({ "fn": 8, "impl": 1, "method": 2, "mod": 3, "struct": 1 }));
    assert_eq!((v["call_edges"].as_u64(), v["call_sites"].as_u64()), (Some(9), Some(13)), "lib 6 + harness 3; charge → audit once");
    assert_eq!((v["tests"].as_u64(), v["files"].as_u64()), (Some(2), Some(3)));
    assert_eq!(v["room"]["edges"]["CALLS"], 9);
    assert_eq!(v["room"]["provenance"]["both"], 2);
    assert_eq!(v["room"]["repeated_keys"], 2);
    assert!(strs(&v["sample_symbols"]).contains(&"shop::checkout".to_string()));
    // every input present; what the producer cannot see yet is a NOTE, not a gap
    assert_eq!(v["state"], "complete", "{v}");
    assert!(missing(&v).is_empty(), "{v}");
    assert!(notes(&v).contains("lower bound"), "{}", notes(&v));
    // `Knowledge.Map` is the same block through the dispatch
    assert_eq!(ask("Knowledge.Map", json!({ "repo": SHOP }))["symbols"], 15);
}

// ------------------------------------------------------------- knowledge

#[test]
fn symbol_lookup_and_defined_in_answer_symbol_rows() {
    let v = ask("Knowledge.SymbolLookup", json!({ "repo": SHOP, "arg": "open", "limit": 0 }));
    let rows = v["symbols"].as_array().unwrap();
    assert_eq!(rows.len(), 2);
    assert_eq!(col(&v["symbols"], "module_path"), s(&["shop::cart", "shop::pay"]));
    let pay = rows.iter().find(|r| r["module_path"] == "shop::pay").unwrap();
    assert_eq!(
        (pay["crate_name"].as_str(), pay["item_kind"].as_str(), pay["item_name"].as_str(), pay["file"].as_str(), pay["line"].as_u64()),
        (Some("shop"), Some("fn"), Some("open"), Some("src/pay.rs"), Some(32))
    );
    assert_eq!((pay["visibility"].as_str(), pay["effective_visibility"].as_str(), pay["doc_lines"].as_u64()), (Some("pub(crate)"), Some("internal"), Some(0)));
    assert!(missing(&v).is_empty() && v["state"] == "complete", "{v}");
    let co = ask("Knowledge.SymbolLookup", json!({ "repo": SHOP, "arg": "checkout" }));
    assert_eq!(
        (co["symbols"][0]["visibility"].as_str(), co["symbols"][0]["effective_visibility"].as_str(), co["symbols"][0]["doc_lines"].as_u64(), co["symbols"][0]["doc"].as_str()),
        (Some("pub"), Some("direct"), Some(1), Some("Check a cart out and charge it."))
    );
    // a method is a `fn` whose module path ends in its type; an impl block names its trait and type
    let add = ask("Knowledge.SymbolLookup", json!({ "repo": SHOP, "arg": "add" }));
    let row = add["symbols"].as_array().unwrap().iter().find(|r| r["item_name"] == "add").unwrap().clone();
    assert_eq!((row["item_kind"].as_str(), row["module_path"].as_str()), (Some("fn"), Some("shop::cart::Cart")));
    let imp = ask("Knowledge.SymbolLookup", json!({ "repo": SHOP, "arg": "impl" }));
    assert_eq!(col(&imp["symbols"], "item_name"), s(&["impl Cart"]));
    // nothing by that name: an empty FACT
    let none = ask("Knowledge.SymbolLookup", json!({ "repo": SHOP, "arg": "zzz" }));
    assert!(none["symbols"].as_array().unwrap().is_empty());
    assert_eq!(none["state"], "empty_fact", "{none}");

    let v = ask("Knowledge.DefinedIn", json!({ "repo": SHOP, "arg": "pay.rs" }));
    assert_eq!(col(&v["symbols"], "item_name"), s(&["audit", "charge", "charges_once", "open", "pay"]), "the ffi declaration is no v1 symbol kind");
    assert_eq!(v["files"], json!(["src/pay.rs"]));
    let none = ask("Knowledge.DefinedIn", json!({ "repo": SHOP, "arg": "nope.rs" }));
    assert!(none["symbols"].as_array().unwrap().is_empty() && notes(&none).contains("no file of the room ends with"), "{none}");
    assert_eq!(refused("Knowledge.SymbolLookup", &shop(), json!({ "repo": SHOP, "arg": "" })).state, State::InvalidArgument);
}

#[test]
fn callers_callees_and_call_path_come_with_their_sites() {
    let v = ask("Knowledge.Callers", json!({ "repo": SHOP, "name": "audit" }));
    let calls = v["calls"].as_array().unwrap();
    assert_eq!(calls.len(), 2, "one row per call site: {v}");
    assert!(calls.iter().all(|c| c["caller_path"] == "shop::pay::charge" && c["callee_ident"] == "shop::pay::audit" && c["file"] == "src/pay.rs" && c["crate_name"] == "shop"));
    assert_eq!(calls.iter().map(|c| c["line"].as_u64().unwrap()).collect::<Vec<_>>(), vec![13, 19], "seq 2 moved charge two lines down");
    assert_eq!(v["state"], "complete");
    assert!(notes(&v).contains("lower bound"));

    let v = ask("Knowledge.Callees", json!({ "repo": SHOP, "name": "checkout" }));
    assert_eq!(col(&v["calls"], "callee_ident"), s(&["shop::cart::Cart::total", "shop::pay::charge", "shop::pay::charge", "shop::pay::charge"]));
    assert_eq!(v["edges"], 2);
    // a path-qualified name picks ONE of the two `open`s
    let v = ask("Knowledge.Callers", json!({ "repo": SHOP, "name": "cart::open" }));
    assert_eq!(col(&v["calls"], "caller_path"), s(&["shop::cart::Cart::total"]));
    // a leaf: nobody calls checkout inside `shop` — a fact
    let v = ask("Knowledge.Callers", json!({ "repo": SHOP, "name": "checkout" }));
    assert!(v["calls"].as_array().unwrap().is_empty());
    assert_eq!(v["state"], "empty_fact");
    // … across every consumed repo, `web` does
    let v = ask("Knowledge.Callers", json!({ "repo": "", "name": "checkout" }));
    assert_eq!(col(&v["calls"], "caller_path"), s(&["web::render"]));
    // a name that is nothing is not "no callers"
    let r = refused("Knowledge.Callers", &shop(), json!({ "repo": SHOP, "name": "nope" }));
    assert_eq!(r.state, State::InvalidArgument);
    assert!(r.note.contains("names no node"), "{}", r.note);

    let v = ask("Knowledge.CallPath", json!({ "repo": SHOP, "from": "checkout", "to": "libc_write" }));
    assert_eq!(strs(&v["names"]), s(&["shop::checkout", "shop::pay::charge", "shop::pay::audit", "shop::pay::libc_write"]));
    assert_eq!(v["hops"], 3);
    assert_eq!(v["path"][1]["file"], "src/pay.rs");
    let v = ask("Knowledge.CallPath", json!({ "repo": SHOP, "from": "libc_write", "to": "checkout" }));
    assert!(v["names"].as_array().unwrap().is_empty());
    assert_eq!(v["state"], "empty_fact", "against the direction: no path, and that is a fact");
}

#[test]
fn feature_gates_are_the_cfg_column_the_gate_edges_and_what_was_compiled_out() {
    // `shop` was dumped without feature nodes: its own `cfg`s are there, and the
    // answer says it cannot see what an OFF feature would add
    let v = ask("Knowledge.FeatureGates", json!({ "repo": SHOP }));
    let gates = v["gates"].as_array().unwrap();
    assert_eq!(col(&v["gates"], "item_name"), s(&["charge", "tests"]));
    let charge = gates.iter().find(|g| g["item_name"] == "charge").unwrap();
    assert_eq!((charge["cfg_expr"].as_str(), charge["module_path"].as_str(), charge["line"].as_u64()), (Some("feature = \"stripe\""), Some("shop::pay"), Some(7)));
    assert_eq!(v["state"], "partial");
    assert!(missing(&v).contains(&"GATED_BY edges".to_string()), "{v}");

    // `v` has them: item → feature gates with their flags, the build's own
    // selection, and the item rustc never saw
    let tiny = Reach::room_only(&fixture::tiny().handle);
    let v = answer("Knowledge.FeatureGates", &tiny, &json!({ "repo": "v" })).unwrap();
    assert_eq!(v["state"], "complete", "{v}");
    assert_eq!(col(&v["gates"], "item_name"), s(&["api"]));
    let by: Vec<(String, bool, bool, bool)> = v["gated_by"]
        .as_array()
        .unwrap()
        .iter()
        .map(|g| (g["item"].as_str().unwrap().to_string(), g["negated"].as_bool().unwrap(), g["partial"].as_bool().unwrap(), g["compiled_out"].as_bool().unwrap()))
        .collect();
    let mut by = by;
    by.sort();
    assert_eq!(by, vec![("v::api".into(), false, false, false), ("v::inner".into(), false, true, false), ("v::legacy".into(), true, false, true)]);
    assert_eq!(v["gated_by"][0]["feature"], "fast");
    assert_eq!(v["features"], json!([{ "crate_name": "v", "feature": "fast", "declared": true, "enabled_in_this_build": true }]));
    let out = &v["gated_out"][0];
    assert_eq!((out["item_name"].as_str(), out["item_kind"].as_str(), out["cfg_expr"].as_str(), out["line"].as_u64()), (Some("legacy"), Some("fn"), Some("not(feature = \"fast\")"), Some(16)));
}

#[test]
fn a_context_slice_is_the_seeds_call_neighbourhood_with_spans() {
    let v = ask("Knowledge.Context", json!({ "repo": SHOP, "query": "how is a cart paid", "seeds": ["checkout"], "hops": 1, "limit": 8 }));
    let slices = v["slices"].as_array().unwrap();
    let got: Vec<(String, u64, u64)> = slices.iter().map(|x| (x["symbols"][0].as_str().unwrap().to_string(), x["radius_hops"].as_u64().unwrap(), x["start_line"].as_u64().unwrap())).collect();
    assert_eq!(got, vec![("shop::checkout".into(), 0, 10), ("shop::cart::Cart::total".into(), 1, 16), ("shop::pay::charge".into(), 1, 7)]);
    assert_eq!(v["ranking"], "call_distance");
    assert!(missing(&v).contains(&"embeddings".to_string()));
    let up = ask("Knowledge.Context", json!({ "repo": SHOP, "seeds": ["audit"], "hops": 1, "include_callers": true }));
    assert!(col(&up["slices"], "file").contains(&"src/pay.rs".to_string()));
    assert!(up["slices"].as_array().unwrap().iter().any(|x| x["symbols"][0] == "shop::pay::charge"), "the caller: {up}");
    // no seeds = the semantic half, which no producer feeds yet
    let r = refused("Knowledge.Context", &shop(), json!({ "repo": SHOP, "query": "how is a cart paid" }));
    assert_eq!(r.state, State::NotWired);
    assert!(r.note.contains("embeddings"), "{}", r.note);
}

#[test]
fn the_knowledge_view_feeds_the_kept_readers() {
    let view = knowledge_view(&shop(), SHOP).unwrap();
    assert_eq!((view.symbols.len(), view.calls.len()), (15, 13));
    // the kept model answers over it: MCP knowledge_*, the funnel's code index
    assert_eq!(view.callers_of("audit").len(), 2);
    assert_eq!(view.callees_of("checkout").len(), 4);
    assert_eq!(view.call_path("checkout", "libc_write"), Some(s(&["checkout", "charge", "audit", "libc_write"])));
    assert_eq!(view.defined_in("cart.rs").len(), 9, "cart, Cart, impl Cart, add, total, open, helper, tests, adds_up");
    let retriever = crate::funnel::decompose::CodeIndexRetriever::new(&view);
    let anchors = crate::funnel::Retriever::retrieve(&retriever, "charge the cart", 5);
    assert!(!anchors.is_empty(), "the funnel grounds on room rows");
    assert_eq!(knowledge_view(&shop(), "").err().map(|r| r.state), Some(State::InvalidArgument));
}

// ------------------------------------------------------------- the linked call graph

#[test]
fn introspect_and_dwarf_walk_source_calls_between_linked_nodes() {
    // checkout and charge are linked; charges_once (a test) and audit are not
    let v = ask("Introspect.Callers", json!({ "binary": "", "name": "charge" }));
    assert_eq!(strs(&v["names"]), s(&["shop::checkout"]), "the test that calls charge is not in the artifact");
    assert_eq!(v["linked_only"], true);
    assert_eq!(v["rows"][0]["sites"], 3);
    assert_eq!(v["rows"][0]["lines"], json!([14, 15, 18]));
    assert!(notes(&v).contains("LINKED nodes only") && notes(&v).contains("lower bound"), "{}", notes(&v));
    // the source graph knows more — that is the difference the evidence names
    let src = ask("Knowledge.Callers", json!({ "repo": SHOP, "name": "charge" }));
    assert_eq!(col(&src["calls"], "caller_path").into_iter().collect::<std::collections::BTreeSet<_>>().len(), 2);

    let v = ask("Dwarf.Callees", json!({ "repo": SHOP, "arg": "charge", "sha": "", "limit": 0 }));
    assert!(v["names"].as_array().unwrap().is_empty(), "audit and the stripe stub are not linked");
    assert_eq!(v["state"], "empty_fact");
    let v = ask("Dwarf.Callees", json!({ "repo": SHOP, "arg": "checkout" }));
    assert_eq!(strs(&v["names"]), s(&["shop::pay::charge"]));
    let v = ask("Introspect.PathBetween", json!({ "binary": "shop", "from": "checkout", "to": "charge" }));
    assert_eq!(strs(&v["names"]), s(&["shop::checkout", "shop::pay::charge"]));
    assert!(notes(&v).contains("artifact `shop`"));
    let v = ask("Dwarf.CallPath", json!({ "repo": SHOP, "from": "checkout", "to": "libc_write" }));
    assert!(v["names"].as_array().unwrap().is_empty(), "the path runs through audit, which is not linked");
    // a linker symbol names its node
    let v = ask("Introspect.Callers", json!({ "binary": "", "name": "_Rcharge" }));
    assert_eq!(strs(&v["names"]), s(&["shop::checkout"]));

    // an artifact the room does not link, a sha it is not at
    let r = refused("Introspect.Callers", &shop(), json!({ "binary": "target/release/nope", "name": "charge" }));
    assert_eq!(r.state, State::InvalidArgument);
    assert!(r.note.contains(ARTIFACT), "names what IS linked: {}", r.note);
    let r = refused("Dwarf.Callers", &shop(), json!({ "repo": SHOP, "arg": "charge", "sha": "0000000" }));
    assert_eq!(r.state, State::InvalidArgument);
    // a repo consumed WITHOUT the binary layer: not "no callers"
    let r = refused("Dwarf.Callers", &shop(), json!({ "repo": WEB, "arg": "render" }));
    assert_eq!(r.state, State::NotConsumed);
    assert!(r.note.contains("binary stream"), "{}", r.note);
    let tiny = Reach::room_only(&fixture::tiny().handle);
    assert_eq!(refused("Introspect.Callees", &tiny, json!({ "binary": "", "name": "api" })).state, State::NotConsumed);
}

// ------------------------------------------------------------- tests, boards, maps

#[test]
fn the_test_inventory_is_the_graphs_test_nodes() {
    let v = ask("Viz.TestMatrix.inventory", Value::Null);
    let rows = v["inventory"].as_array().unwrap();
    assert_eq!(col(&v["inventory"], "test_name"), s(&["adds_up", "charges_once"]));
    let t = rows.iter().find(|r| r["test_name"] == "adds_up").unwrap();
    assert_eq!(
        (t["repo"].as_str(), t["crate_name"].as_str(), t["module_path"].as_str(), t["file"].as_str(), t["line"].as_u64()),
        (Some(SHOP), Some("shop"), Some("shop::cart::tests"), Some("src/cart.rs"), Some(50))
    );
    assert_eq!(t["is_heavy"], false, "a test without `#[ignore]`: {t}");
    // `charges_once` is a row from before the lake had the column (evolved
    // from mimir-schema 2, not consumed again): unknown, and said so
    let old = rows.iter().find(|r| r["test_name"] == "charges_once").unwrap();
    assert!(old.get("is_heavy").is_none(), "unknown is left out, never `false`: {old}");
    assert!(missing(&v).contains(&"is_heavy".to_string()));
    // the CLI listing: no warehouse behind this door, so no join — said, not `X` everywhere
    let l = ask("Test.List", json!({ "repo": SHOP }));
    assert_eq!(l["results_state"], "not_joined");
    assert_eq!(l["inventory"].as_array().unwrap().len(), 2);
    assert!(l["inventory"][0].get("status").is_none());
    assert!(missing(&l).contains(&"test_results".to_string()));
    let web = ask("Test.List", json!({ "repo": WEB }));
    assert!(web["inventory"].as_array().unwrap().is_empty(), "web has no test — with the inputs it needs, a fact up to the named gaps");
}

#[test]
fn the_architecture_board_is_the_kept_classifier_over_room_rows() {
    let (payload, ev) = arch_payload(&shop()).unwrap();
    let ids: Vec<&str> = payload.graph.nodes.iter().map(|n| n.id.as_str()).collect();
    assert_eq!(ids, vec!["corefn:shop", "corefn:shop::cart", "corefn:shop::pay", "corefn:stripe::Client", "corefn:web"]);
    let edges: Vec<(&str, &str)> = payload.graph.edges.iter().map(|e| (e.from.as_str(), e.to.as_str())).collect();
    assert_eq!(
        edges,
        vec![("corefn:shop", "corefn:shop::cart"), ("corefn:shop", "corefn:shop::pay"), ("corefn:shop::pay", "corefn:stripe::Client"), ("corefn:web", "corefn:shop")]
    );
    assert_eq!(payload.members_with_data, s(&[SHOP, WEB]));
    assert_eq!((payload.symbols.len(), payload.calls.len()), (16, 14), "the metro fuel: shop 15 + web 1 symbols, 14 call sites");
    assert_eq!(payload.metro_fuel_source, "resolved/scip", "rustc resolved every callee");
    assert!(payload.errors.is_empty() && payload.coverage.is_empty());
    // shop touches no warehouse table, and this lake was written with the
    // column that says so: no Table node is a fact, not a missing input
    assert!(!ev.missing.iter().any(|m| m.input == "TOUCHES_TABLE edges"), "{ev}");
    assert!(payload.access.is_empty(), "no gRPC handler, no table: no terminus");
    // the wire: the same payload, with its evidence
    let v = ask("Viz.Architecture", json!({ "workspace": "" }));
    assert_eq!(v["graph"]["nodes"].as_array().unwrap().len(), 5);

    // per repo: the typed board, its SVG, a trace, click-to-code, history
    let g = arch_graph(&shop(), SHOP).unwrap();
    assert_eq!(g.nodes.len(), 4, "shop, shop::cart, shop::pay, stripe::Client");
    let v = ask("Arch.Generate", json!({ "repo": SHOP }));
    assert_eq!((v["nodes"].as_u64(), v["edges"].as_u64(), v["historized"].as_bool()), (Some(4), Some(3), Some(false)));
    assert!(v["svg"].as_str().is_some_and(|s| s.starts_with("<svg") || s.contains("<svg")));
    let v = ask("Arch.Trace", json!({ "repo": SHOP, "entrypoint": "shop::pay" }));
    assert_eq!(v["graph"]["nodes"].as_array().unwrap().iter().map(|n| n["id"].as_str().unwrap()).collect::<Vec<_>>(), vec!["corefn:shop::pay", "corefn:stripe::Client"]);
    let r = refused("Arch.Trace", &shop(), json!({ "repo": SHOP, "entrypoint": "zzz" }));
    assert_eq!(r.state, State::InvalidArgument);
    let v = ask("Arch.Open", json!({ "repo": SHOP, "symbol": "charge" }));
    assert_eq!((v["locations"][0]["symbol"].as_str(), v["locations"][0]["file"].as_str(), v["locations"][0]["line"].as_u64()), (Some("charge"), Some("src/pay.rs"), Some(7)));
    let v = ask("Arch.History", json!({ "repo": SHOP }));
    let h = v["history"].as_array().unwrap();
    assert_eq!(h.iter().map(|r| (r["seq"].as_i64().unwrap(), r["nodes"].as_u64().unwrap())).collect::<Vec<_>>(), vec![(2, 4), (1, 4)]);
    assert_eq!(h[0]["added_nodes"], json!([]), "seq 2 only moved code: the same board");
    assert_eq!(ask("Arch.Graph", json!({ "repo": WEB }))["graph"]["nodes"].as_array().unwrap().len(), 2, "web and the shop bucket it calls");
}

#[test]
fn the_knowledge_map_has_a_bubble_per_local_crate() {
    let (summary, ev) = knowledge_summary(&shop()).unwrap();
    let b: Vec<(&str, &str, usize, usize, usize, usize, i64)> =
        summary.crates.iter().map(|b| (b.repo.as_str(), b.krate.as_str(), b.symbols, b.calls, b.files, b.gates, b.heat_30d)).collect();
    assert_eq!(b, vec![(SHOP, "shop", 15, 9, 3, 2, 0), (WEB, "web", 1, 1, 1, 0, 0)], "no bubble for the stripe stub or the linker import");
    let r: Vec<(&str, bool, usize, usize, usize, usize)> = summary.repos.iter().map(|r| (r.repo.as_str(), r.ok, r.symbols, r.calls, r.features, r.git_files)).collect();
    assert_eq!(r, vec![(SHOP, true, 15, 9, 2, 3), (WEB, true, 1, 1, 0, 1)]);
    assert!(ev.missing.iter().any(|m| m.input == "git_heat_facts"), "heat 0 is named as unread: {ev}");
    let v = ask("Viz.Knowledge", json!({ "workspace": "" }));
    assert_eq!(v["crates"][0]["krate"], "shop");
    assert_eq!(v["repos"].as_array().unwrap().len(), 2);
    assert_eq!(v["state"], "partial");
}

/// 30-day heat is the repo's NEWEST git-heat scan joined on the files the
/// crate's items lie in; a repo without a scan is named, not shown cold.
#[test]
fn the_knowledge_map_joins_the_git_heat_feed() {
    use crate::knowledge::git_heat::{GitHeatRow, GitHeatScan};
    let dir = tempfile::tempdir().unwrap();
    let wh = crate::warehouse::iceberg::IcebergWarehouse::open(dir.path()).unwrap();
    let reach = Reach::new(&fixture::shop().handle, &wh);
    let heat_of = |reach: &Reach<'_>| {
        let (summary, ev) = knowledge_summary(reach).unwrap();
        let heat: Vec<(String, i64)> = summary.crates.iter().map(|b| (b.krate.clone(), b.heat_30d)).collect();
        let unread: Vec<Option<String>> = ev.missing.iter().filter(|m| m.input == "git_heat_facts").map(|m| m.repo.clone()).collect();
        (heat, unread)
    };
    // the table is there and empty: the feed is what is missing, for every repo
    assert_eq!(heat_of(&reach), (vec![("shop".to_string(), 0), ("web".to_string(), 0)], vec![None]));

    let scan = |at_micros: i64, files: &[(&str, i64)]| GitHeatScan {
        snapshot_id: uuid::Uuid::new_v4(),
        ts: chrono::DateTime::from_timestamp_micros(at_micros).unwrap(),
        repo: SHOP.into(),
        files: files
            .iter()
            .map(|(f, d30)| GitHeatRow { file: (*f).into(), commits_total: 100, commits_30d: *d30, commits_90d: 50, authors_total: 2, last_commit_ts: chrono::DateTime::from_timestamp_micros(at_micros).unwrap() })
            .collect(),
    };
    // an older scan (pay.rs was hotter then), and the newest one: only that counts
    wh.append_git_heat_scan(&scan(1_000_000, &[("src/pay.rs", 99)])).unwrap();
    wh.append_git_heat_scan(&scan(2_000_000, &[("src/pay.rs", 7), ("src/cart.rs", 3), ("src/lib.rs", 1), ("README.md", 50)])).unwrap();
    let (heat, unread) = heat_of(&reach);
    assert_eq!(heat, vec![("shop".to_string(), 7), ("web".to_string(), 0)], "shop's hottest SOURCE file; README.md holds no item of the crate");
    assert_eq!(unread, vec![Some(WEB.to_string())], "web has no scan: named, shop is not");
}

#[test]
fn the_call_graph_lens_and_the_repo_edges() {
    let (g, ev) = call_graph(&shop(), SHOP, 100).unwrap();
    let nodes = g["nodes"].as_array().unwrap();
    let edges = g["edges"].as_array().unwrap();
    assert_eq!(g["total_edges"], 7, "calls between shop's own fns and methods (the stripe stub and the ffi declaration are not)");
    assert_eq!(edges.len(), 7);
    assert_eq!(edges[0]["sites"], 3, "heaviest first: checkout → charge");
    assert_eq!((nodes[edges[0]["from"].as_u64().unwrap() as usize]["id"].as_str(), nodes[edges[0]["to"].as_u64().unwrap() as usize]["id"].as_str()), (Some("shop::checkout"), Some("shop::pay::charge")));
    let prov = |id: &str| nodes.iter().find(|n| n["id"] == id).map(|n| n["provenance"].as_str().unwrap_or("").to_string());
    assert_eq!(prov("shop::checkout").as_deref(), Some("both"));
    assert_eq!(prov("shop::pay::audit").as_deref(), Some("source_only"));
    assert!(ev.notes.iter().any(|n| n.contains("lower bound")));
    let (capped, ev) = call_graph(&shop(), SHOP, 2).unwrap();
    assert_eq!((capped["edges"].as_array().unwrap().len(), capped["total_edges"].as_u64()), (2, Some(7)));
    assert_eq!(ev.capped.map(|c| (c.shown, c.total)), Some((2, 7)));

    let (edges, _) = repo_edges(&shop()).unwrap();
    assert_eq!(edges, vec![(WEB.to_string(), SHOP.to_string(), 1)], "web calls into shop; nothing the other way");
}

// ------------------------------------------------------------- templates and the rest

#[test]
fn the_sql_templates_are_questions_to_the_room() {
    let menu = ask("Mimir.SqlTemplate", json!({ "template": "", "params": {} }));
    assert_eq!(col(&menu["templates"], "name"), s(&["call-chain", "change-radius", "def-use", "table-access-lineage"]));
    assert!(menu["templates"].as_array().unwrap().iter().all(|t| t["state"] == "code_room"), "every template is answered by the room: {menu}");

    let v = ask("Mimir.SqlTemplate", json!({ "template": "def-use", "params": { "repo": SHOP, "symbol": "Cart" } }));
    assert_eq!(col(&v["definitions"], "item_name"), s(&["Cart"]));
    let uses: Vec<(String, String)> = v["uses"].as_array().unwrap().iter().map(|u| (u["kind"].as_str().unwrap().to_string(), u["user"].as_str().unwrap().to_string())).collect();
    assert_eq!(uses, vec![("FOR_TYPE".into(), "shop::cart::Cart".into()), ("USES_TYPE".into(), "shop::checkout".into())]);
    assert_eq!(v["uses"][1]["lines"], json!([11]));

    let v = ask("Mimir.SqlTemplate", json!({ "template": "call-chain", "params": { "repo": SHOP, "symbol": "charge" } }));
    assert_eq!(col(&v["callers"], "caller"), s(&["shop::checkout", "shop::pay::charges_once"]));
    assert_eq!(col(&v["callees"], "callee"), s(&["shop::pay::audit", "stripe::Client::send"]));

    let v = ask("Mimir.SqlTemplate", json!({ "template": "change-radius", "params": { "repo": SHOP, "file": "cart.rs" } }));
    assert!(col(&v["symbols"], "symbol").contains(&"shop::cart::Cart::total".to_string()));
    assert_eq!(col(&v["affected"], "symbol"), s(&["shop::checkout"]), "outside the file: the fn that calls total and uses Cart");

    // a table no fn of the scope touches is a name that resolves to nothing — never "no reader"
    let r = refused("Mimir.SqlTemplate", &shop(), json!({ "template": "table-access-lineage", "params": { "table": "bench_runs" } }));
    assert_eq!(r.state, State::InvalidArgument);
    assert!(r.note.contains("no fn touches a table named `bench_runs`") && r.note.contains("0 table(s)"), "{}", r.note);
    assert_eq!(ask("Mimir.SqlTemplate", json!({ "template": "def-use", "render_only": true }))["sql"], Value::Null);
    assert_eq!(refused("Mimir.SqlTemplate", &shop(), json!({ "template": "nope", "params": {} })).state, State::InvalidArgument);
    assert_eq!(refused("Mimir.SqlTemplate", &shop(), json!({ "template": "change-radius", "params": { "repo": SHOP, "file": "nope.rs" } })).state, State::InvalidArgument);
}

#[test]
fn snapshot_diff_retrieval_and_what_stays_unwired() {
    let v = ask("Coderoom.SnapshotDiff", json!({ "snap_a": "shop@1", "snap_b": "shop@2" }));
    assert_eq!((v["added_nodes"].as_u64(), v["removed_nodes"].as_u64(), v["changed_nodes"].as_u64()), (Some(0), Some(0), Some(0)));
    assert_eq!(v["state"], "empty_fact", "seq 2 moved code: spans only, nothing semantic");
    assert_eq!(refused("Coderoom.SnapshotDiff", &shop(), json!({ "snap_a": "a1b2", "snap_b": "c3d4" })).state, State::InvalidArgument);
    assert_eq!(refused("Coderoom.SnapshotDiff", &shop(), json!({ "snap_a": "shop@1", "snap_b": "shop@9" })).state, State::InvalidArgument, "a seq it never had");

    let v = ask("Funnel.Retrieve", json!({ "repo": SHOP, "query": "fix the charge audit trail", "limit": 5 }));
    assert_eq!(col(&v["anchors"], "symbol"), s(&["shop::pay::audit", "shop::pay::charge", "shop::pay::charges_once"]));
    assert_eq!(v["anchors"][0]["file"], "src/pay.rs");

    for (surface, word) in [("Coderoom.Ingest", "world ring"), ("Coderoom.Compat", "world ring"), ("Coderoom.WhatBreaks", "world ring")] {
        let r = refused(surface, &shop(), json!({ "crate": "serde" }));
        assert_eq!(r.state, State::NotWired, "{surface}");
        assert!(r.note.contains(word), "{surface}: {}", r.note);
    }
    let r = refused("Vector.SlicesIndex", &shop(), json!({ "repo": SHOP }));
    assert_eq!(r.state, State::NotWired);
    assert!(r.note.contains("19 item spans"), "{}", r.note);
}

/// The API surface the completeness gate reads: the tests, and the fns of the
/// nameable API — `charge` is `pub` in a private module and is NOT on it.
#[test]
fn the_api_surface_is_the_effective_visibility_not_the_keyword() {
    let api = super::super::api_surface(&shop(), SHOP).unwrap();
    let mut fns: Vec<(&str, bool)> = api.fns.iter().map(|f| (f.path.as_str(), f.is_test)).collect();
    fns.sort();
    assert_eq!(
        fns,
        vec![
            ("shop::cart::Cart::add", false),
            ("shop::cart::Cart::total", false),
            ("shop::cart::open", false),
            ("shop::cart::tests::adds_up", true),
            ("shop::checkout", false),
            ("shop::pay::charges_once", true),
        ]
    );
    assert!(api.calls.contains(&("adds_up".to_string(), "add".to_string())) && api.calls.contains(&("charge".to_string(), "audit".to_string())));
    assert!(api.notes.iter().any(|n| n.contains("lower bound")));
    assert_eq!(super::super::api_surface(&shop(), "").unwrap_err().state, State::InvalidArgument);
    assert_eq!(super::super::api_surface(&Reach::room_only(&fixture::unconsumed().handle), SHOP).unwrap_err().state, State::NotConsumed);
}

/// `#[ignore]` (mimir-schema 3) reaches the inventory as `is_heavy`, and a
/// column the room has no field for flows into the rows by name.
#[test]
fn an_ignored_test_is_heavy() {
    let tiny = Reach::room_only(&fixture::tiny().handle);
    let (rows, ev) = test_inventory(&tiny, "v").unwrap();
    assert_eq!(rows.iter().map(|r| (r["test_name"].as_str().unwrap(), r["is_heavy"].as_bool())).collect::<Vec<_>>(), vec![("slow_test", Some(true))]);
    assert!(!ev.missing.iter().any(|m| m.input == "is_heavy"), "every test of `v` has the value: {ev}");

    let room = fixture::extras_room();
    assert!(room.has_attr("arity"));
    let (symbols, _, ev) = view_rows(&room, Some("v")).unwrap();
    let got: Vec<(&str, &str, u32)> = symbols.iter().map(|s| (s.item_name.as_str(), s.visibility.as_str(), s.doc_lines)).collect();
    assert_eq!(got, vec![("api", "pub", 1), ("inner", "private", 0), ("slow_test", "private", 0)]);
    assert!(!ev.missing.iter().any(|m| m.input == "visibility"), "{ev}");
}

// ------------------------------------------------------------- not consumed

/// Every surface that needs a room, asked of a workspace nothing was
/// consumed into: the state, never an empty answer.
#[test]
fn nothing_consumed_is_a_state_on_every_surface() {
    let fresh = Reach::room_only(&fixture::unconsumed().handle);
    let per_repo = json!({
        "repo": "shop", "arg": "open", "name": "open", "from": "a", "to": "b", "symbol": "open", "entrypoint": "x", "query": "open the cart",
        "seeds": ["open"], "template": "call-chain", "params": { "repo": "shop", "symbol": "open", "file": "lib.rs" },
        "snap_a": "shop@1", "snap_b": "shop@2",
    });
    let whole = json!({ "workspace": "", "binary": "", "name": "open", "from": "a", "to": "b", "arg": "open", "template": "def-use", "params": { "symbol": "open" } });
    // a board, its history and a diff are per repo by definition: without one
    // the request itself is wrong, whatever is consumed
    // Test.Affected asks about one member's tests: a repo by definition too
    let needs_a_repo = ["Arch.Generate", "Arch.Trace", "Arch.Open", "Arch.Graph", "Arch.History", "Coderoom.SnapshotDiff", "Test.Affected"];
    let mut asked = 0;
    for surface in super::super::SURFACES {
        if ["Coderoom.Ingest", "Coderoom.Compat", "Coderoom.WhatBreaks"].contains(surface) {
            // no room would help: the producer is missing, whatever is consumed
            assert_eq!(refused(surface, &fresh, per_repo.clone()).state, State::NotWired, "{surface}");
            continue;
        }
        if *surface == "Coderoom.Artifacts" {
            // the built artifacts are not a room either: none landed here
            let v = answer(surface, &fresh, &whole).expect("the artifacts answer without a room");
            assert_eq!(v["state"], "empty_fact", "{v}");
            continue;
        }
        if *surface == "Coderoom.Units" {
            // the build board is about the builds, not the room: it answers
            // while the FIRST read of a workspace runs, before anything is
            // consumed — here, with no build in this process, an empty fact
            let v = answer(surface, &fresh, &per_repo).expect("the board answers without a room");
            assert_eq!(v["state"], "empty_fact", "{v}");
            continue;
        }
        let r = refused(surface, &fresh, per_repo.clone());
        assert_eq!(r.state, State::NotConsumed, "{surface} for a repo: [{}] {}", r.state, r.note);
        assert!(r.note.contains("consume"), "{surface}: {}", r.note);
        let r = refused(surface, &fresh, whole.clone());
        let want = if needs_a_repo.contains(surface) { State::InvalidArgument } else { State::NotConsumed };
        assert_eq!(r.state, want, "{surface} for the whole workspace: [{}] {}", r.state, r.note);
        asked += 1;
    }
    assert_eq!(asked, super::super::SURFACES.len() - 5);
    // the typed entries, and the block
    assert_eq!(knowledge_view(&fresh, "shop").err().map(|r| r.state), Some(State::NotConsumed));
    assert_eq!(arch_graph(&fresh, "shop").unwrap_err().state, State::NotConsumed);
    assert_eq!(knowledge_block(&fresh, "shop").unwrap_err().state, State::NotConsumed);
    assert_eq!(knowledge_summary(&fresh).unwrap_err().state, State::NotConsumed);
    assert_eq!(arch_payload(&fresh).unwrap_err().state, State::NotConsumed);
    assert_eq!(test_inventory(&fresh, "").unwrap_err().state, State::NotConsumed);
    assert_eq!(call_graph(&fresh, "shop", 10).unwrap_err().state, State::NotConsumed);
    assert_eq!(repo_edges(&fresh).unwrap_err().state, State::NotConsumed);
    // a repo the workspace has NOT consumed, beside ones it has
    let r = refused("Knowledge.Callers", &shop(), json!({ "repo": "nobody", "name": "open" }));
    assert_eq!(r.state, State::NotConsumed);
    assert!(r.note.contains("nobody") && r.note.contains("shop"), "names the repo and what IS consumed: {}", r.note);
    // a door with no room at all is told THAT, whatever it asked — even a request
    // that is malformed besides (the seam guard asks every surface with nothing)
    assert_eq!(refused("Knowledge.Callers", &Reach::none(), json!({ "repo": "shop", "name": "open" })).state, State::NoRoom);
    for surface in super::super::SURFACES.iter().filter(|s| **s != "Mimir.SqlTemplate") {
        // (the template MENU needs no room and answers; a template itself does)
        let r = refused(surface, &Reach::none(), Value::Null);
        assert!(matches!(r.state, State::NoRoom | State::NotWired), "{surface}: [{}] {}", r.state, r.note);
    }
}

// ------------------------------------------------------------- the panes' readers

fn row<'a>(rows: &'a Value, key: &str, want: &str) -> &'a Value {
    rows.as_array().unwrap_or_else(|| panic!("not rows: {rows}")).iter().find(|r| r[key] == want).unwrap_or_else(|| panic!("no row with {key} = {want} in {rows}"))
}

/// The room every pane surface names: workspace, repo@seq with the commit,
/// node and edge counts — the numbers a pane prints to be compared.
#[test]
fn a_pane_answer_names_the_room_it_was_read_from() {
    let v = ask("Viz.CrateGraph", json!({}));
    let room = &v["room"];
    assert_eq!((room["workspace"].as_str(), room["universe"].as_bool(), room["nodes"].as_u64(), room["edges_total"].as_u64()), (Some("ws"), Some(false), Some(24), Some(35)));
    assert_eq!(room["edges"], json!({ "CALLS": 10, "CONTAINS": 19, "DEPENDS_ON": 1, "FOR_TYPE": 1, "TESTS": 3, "USES_TYPE": 1 }));
    assert_eq!(col(&room["repos"], "repo"), s(&[SHOP, WEB]));
    let shop_at = row(&room["repos"], "repo", SHOP);
    assert_eq!(shop_at["seq"], 2);
    assert!(shop_at["sha"].as_str().is_some_and(|x| x.len() == 40), "{shop_at}");
    // one repo asked ⇒ that repo's room
    let one = ask("Viz.CallGraph", json!({ "repo": SHOP }));
    assert_eq!((one["room"]["nodes"].as_u64(), one["room"]["edges_total"].as_u64()), (Some(22), Some(33)));
    // the ring is named when it is folded in
    assert_eq!(ask("Viz.CrateGraph", json!({ "universe": true }))["room"]["universe"], true);
}

#[test]
fn the_crate_graph_is_the_quotient_by_crate_with_what_joins_each_pair() {
    let v = ask("Viz.CrateGraph", json!({}));
    assert_eq!(col(&v["crates"], "id"), s(&["extern@0", "shop@0.1.0", "stripe@2.0.0", "web@0.2.0"]));
    let shop_crate = row(&v["crates"], "id", "shop@0.1.0");
    assert_eq!(
        (shop_crate["local"].as_bool(), shop_crate["repo"].as_str(), shop_crate["nodes"].as_u64(), shop_crate["symbols"].as_u64(), shop_crate["fns"].as_u64(), shop_crate["files"].as_u64(), shop_crate["calls_inside"].as_u64()),
        (Some(true), Some(SHOP), Some(19), Some(15), Some(10), Some(3), Some(8)),
        "{shop_crate}"
    );
    // a dependency is not a crate of the workspace: no repo, and (ring off) only its stubs
    let stripe = row(&v["crates"], "id", "stripe@2.0.0");
    assert_eq!((stripe["local"].as_bool(), stripe["repo"].is_null(), stripe["nodes"].as_u64()), (Some(false), true, Some(2)));
    assert!(notes(&v).contains("ring off: a dependency crate is here only as the reference stubs"), "{}", notes(&v));
    // what joins each pair, by kind, with counts
    assert_eq!(
        v["edges"],
        json!([
            { "from": "shop@0.1.0", "to": "stripe@2.0.0", "depends_on": 1, "calls": 1, "call_sites": 1, "uses_type": 0 },
            { "from": "web@0.2.0", "to": "shop@0.1.0", "depends_on": 0, "calls": 1, "call_sites": 1, "uses_type": 0 },
        ])
    );
    // per repo: the crates it defines and the crates those depend on; repo → repo
    let shop_repo = row(&v["repos"], "repo", SHOP);
    assert_eq!((shop_repo["crates"].clone(), shop_repo["consumes"].clone(), shop_repo["seq"].as_u64()), (json!(["shop@0.1.0"]), json!(["stripe"]), Some(2)));
    assert_eq!(row(&v["repos"], "repo", WEB)["consumes"], json!([]));
    assert_eq!(v["repo_edges"], json!([{ "from": WEB, "to": SHOP, "depends_on": 0, "calls": 1, "via": [] }]));
    assert_eq!(v["state"], "complete", "{v}");
}

#[test]
fn the_function_tier_is_each_crates_fns_and_the_calls_among_them() {
    // the crate's fns, asked of the crate (the whole room's tier is a summary)
    let v = ask("Viz.FunctionTier", json!({ "crate": "shop", "page_size": 100 }));
    assert_eq!((v["total_fns"].as_u64(), v["total_calls"].as_u64()), (Some(10), Some(7)));
    let shop_tier = &row(&v["repos"], "repo", SHOP)["crates"][0];
    assert_eq!((shop_tier["crate"].as_str(), shop_tier["total_fns"].as_u64(), shop_tier["total_calls"].as_u64()), (Some("shop"), Some(10), Some(7)));
    let fns = shop_tier["fns"].as_array().unwrap();
    let at = |id: &str| fns.iter().position(|f| f["id"] == id).unwrap_or_else(|| panic!("no fn {id}")) as u64;
    assert_eq!(fns[at("shop::pay::charge") as usize]["name"], "charge");
    // a call is a pair of indexes into THIS crate's fns, with its sites
    assert!(shop_tier["calls"].as_array().unwrap().contains(&json!([at("shop::checkout"), at("shop::pay::charge"), 3])), "{}", shop_tier["calls"]);
    assert_eq!(shop_tier["calls"].as_array().unwrap().len(), 7);
    let all = ask("Viz.FunctionTier", json!({}));
    assert_eq!((all["total_fns"].as_u64(), all["total_calls"].as_u64()), (Some(11), Some(8)));
    let web_tier = &row(&all["repos"], "repo", WEB)["crates"][0];
    assert_eq!((web_tier["total_fns"].as_u64(), web_tier["calls"].as_array().map(Vec::len)), (Some(1), Some(0)));
    assert!(notes(&all).contains("1 call edge(s) between local fns cross a crate"), "{}", notes(&all));
    // the call graph through the dispatch carries the same graph the lens reads
    let g = ask("Viz.CallGraph", json!({ "repo": SHOP, "limit": 2 }));
    assert_eq!((g["edges"].as_array().unwrap().len(), g["total_edges"].as_u64(), g["evidence"]["capped"]["total"].as_u64()), (2, Some(7), Some(7)));
}

/// The whole room's function tier is a SUMMARY by default — per repo, per
/// crate, its counts and no fn — so the answer stays small however big the
/// room is (it was 37 MB for `nordisk`). `per_crate` previews the first fns
/// of each crate; `crate` drills into one crate, a page at a time
/// (`page`, `page_size`), and the pages together are the crate's fns and
/// calls exactly once.
///
/// RED WHEN REVERTED: the old reader hands every fn of every crate on `{}`
/// (up to 120 000), ignores `per_crate`, `crate` and `page`.
#[test]
fn the_function_tier_is_a_summary_by_default_and_a_crate_is_read_a_page_at_a_time() {
    let v = ask("Viz.FunctionTier", json!({}));
    assert_eq!(v["mode"], "summary", "{v}");
    assert_eq!((v["total_fns"].as_u64(), v["total_calls"].as_u64()), (Some(11), Some(8)));
    let shop_tier = &row(&v["repos"], "repo", SHOP)["crates"][0];
    assert_eq!((shop_tier["total_fns"].as_u64(), shop_tier["total_calls"].as_u64()), (Some(10), Some(7)));
    assert_eq!((shop_tier["fns"].as_array().map(Vec::len), shop_tier["calls"].as_array().map(Vec::len)), (Some(0), Some(0)), "a summary names no fn: {shop_tier}");
    assert_eq!((v["evidence"]["capped"]["shown"].as_u64(), v["evidence"]["capped"]["total"].as_u64()), (Some(0), Some(11)), "what is left out is said");
    // a preview: the first fns of each crate, the calls from them
    let p = ask("Viz.FunctionTier", json!({ "per_crate": 2 }));
    let shop_tier = &row(&p["repos"], "repo", SHOP)["crates"][0];
    assert_eq!((shop_tier["fns"].as_array().map(Vec::len), shop_tier["offset"].as_u64()), (Some(2), Some(0)));
    assert!(shop_tier["calls"].as_array().unwrap().iter().all(|c| c[0].as_u64() < Some(2)), "calls from a shown fn: {}", shop_tier["calls"]);
    // the crate, a page at a time
    let whole = ask("Viz.FunctionTier", json!({ "repo": SHOP, "crate": "shop", "page_size": 100 }));
    let whole = &row(&whole["repos"], "repo", SHOP)["crates"][0];
    let (mut ids, mut calls) = (Vec::new(), Vec::new());
    let mut page = 0u64;
    loop {
        let a = ask("Viz.FunctionTier", json!({ "repo": SHOP, "crate": "shop", "page": page, "page_size": 4 }));
        assert_eq!(a["mode"], "crate", "{a}");
        let t = &row(&a["repos"], "repo", SHOP)["crates"][0];
        assert_eq!((t["offset"].as_u64(), t["pages"].as_u64(), t["page"].as_u64()), (Some(page * 4), Some(3), Some(page)), "{t}");
        assert!(t["fns"].as_array().unwrap().len() <= 4);
        ids.extend(t["fns"].as_array().unwrap().iter().map(|f| f["id"].clone()));
        calls.extend(t["calls"].as_array().unwrap().iter().cloned());
        match t["next_page"].as_u64() {
            Some(n) => page = n,
            None => break,
        }
    }
    assert_eq!(page, 2, "10 fns, 4 a page: three pages");
    assert_eq!(ids, whole["fns"].as_array().unwrap().iter().map(|f| f["id"].clone()).collect::<Vec<_>>(), "the pages are the crate's fns, in order, once");
    calls.sort_by_key(|c| c.to_string());
    let mut want = whole["calls"].as_array().unwrap().clone();
    want.sort_by_key(|c| c.to_string());
    assert_eq!((calls.len(), calls), (7, want), "each call once, on the page of its caller, indexes into the crate's fns");
    // a crate the room does not hold: an empty answer that says so
    let none = ask("Viz.FunctionTier", json!({ "crate": "nope" }));
    assert_eq!((none["total_fns"].as_u64(), none["repos"].as_array().map(Vec::len)), (Some(0), Some(0)));
}

#[test]
fn a_symbol_listing_is_capped_and_says_so() {
    let v = ask("Knowledge.Symbols", json!({ "repo": SHOP, "kinds": ["fn"] }));
    assert_eq!((v["total"].as_u64(), v["symbols"].as_array().unwrap().len()), (Some(8), 8));
    assert_eq!(v["by_kind"], json!({ "fn": 8, "impl": 1, "method": 2, "mod": 3, "struct": 1 }));
    let charge = row(&v["symbols"], "path", "shop::pay::charge");
    assert_eq!((charge["file"].as_str(), charge["line"].as_u64(), charge["end_line"].as_u64(), charge["moniker"].as_str()), (Some("src/pay.rs"), Some(7), Some(22), Some(m(CHARGE).as_str())));
    let cut = ask("Knowledge.Symbols", json!({ "repo": SHOP, "limit": 2 }));
    assert_eq!((cut["symbols"].as_array().unwrap().len(), cut["total"].as_u64()), (2, Some(15)));
    assert_eq!((cut["evidence"]["capped"]["shown"].as_u64(), cut["evidence"]["capped"]["total"].as_u64()), (Some(2), Some(15)));
}

#[test]
fn the_source_of_an_item_is_its_span_and_the_text_at_the_consumed_commit() {
    // no clone of the repo beside the lake yet: the item is LOCATED, the text is a named gap
    let v = ask("Knowledge.Source", json!({ "repo": SHOP, "name": "shop::checkout" }));
    assert_eq!((v["file"].as_str(), v["start_line"].as_u64(), v["end_line"].as_u64(), v["repo"].as_str()), (Some("src/lib.rs"), Some(10), Some(20), Some(SHOP)));
    assert_eq!((v["state"].as_str(), v["lines"].as_array().map(Vec::len)), (Some("partial"), Some(0)));
    assert_eq!(missing(&v), s(&["source text"]));
    assert!(v["sha"].as_str().is_some_and(|x| x.len() == 40), "{v}");
    // the consumer's clone, where the layout says it is (the fixture consumed from `src-shop`)
    let base = fixture::shop().handle.layout().base().to_path_buf();
    std::fs::create_dir_all(base.join("clones")).unwrap();
    let _ = std::os::unix::fs::symlink(base.join("src-shop"), base.join("clones").join(SHOP));
    // the crate root's span starts at line 1: the blob at the offset commit is read
    let v = ask("Knowledge.Source", json!({ "moniker": m(CRATE) }));
    assert_eq!((v["file"].as_str(), v["start_line"].as_u64(), v["file_lines"].as_u64()), (Some("src/lib.rs"), Some(1), Some(1)), "{v}");
    assert_eq!(v["lines"], json!(["// commit 1"]), "the scratch repo's second commit, as committed");
    assert_eq!(v["state"], "complete", "{v}");
    // a span the file at that commit does not have is said, never padded
    let v = ask("Knowledge.Source", json!({ "repo": SHOP, "name": "shop::checkout" }));
    assert_eq!((v["state"].as_str(), v["lines"].as_array().map(Vec::len), v["file_lines"].as_u64()), (Some("partial"), Some(0), Some(1)));
    assert!(v["evidence"]["missing"][0]["why"].as_str().unwrap().contains("has 1 line(s); the span 10–20 lies outside it"), "{v}");
    // a node with no span (a dependency stub) is located nowhere: an empty GAP
    let v = ask("Knowledge.Source", json!({ "name": "send" }));
    assert_eq!((v["state"].as_str(), missing(&v)), (Some("empty_gap"), s(&["span"])));
    assert_eq!(v["node"]["path"], "stripe::Client::send");
    // a name that is no node is an argument error, as on every surface
    assert_eq!(refused("Knowledge.Source", &shop(), json!({ "name": "zzz_nothing" })).state, State::InvalidArgument);
    assert_eq!(refused("Knowledge.Source", &shop(), json!({})).state, State::InvalidArgument);
}

#[test]
fn test_reach_is_the_rooms_walk_from_the_tests() {
    let v = ask("Knowledge.TestReach", json!({ "repo": SHOP }));
    assert_eq!((v["surface_fns"].as_u64(), v["test_reachable"].as_u64(), v["tests_total"].as_u64(), v["fns"].as_array().map(Vec::len)), (Some(8), Some(5), Some(2), Some(10)));
    let f = |fqn: &str| row(&v["fns"], "fqn", fqn).clone();
    // reached through a chain: adds_up → total → cart::open; charges_once → charge → audit
    for (fqn, reached, fan_in) in [
        ("shop::cart::Cart::add", true, 2),
        ("shop::cart::Cart::total", true, 2),
        ("shop::cart::open", true, 1),
        ("shop::pay::charge", true, 4),
        ("shop::pay::audit", true, 2),
        ("shop::checkout", false, 0),
        ("shop::pay::open", false, 0),
        ("shop::cart::helper", false, 0),
    ] {
        let r = f(fqn);
        assert_eq!((r["test_reachable"].as_bool(), r["fan_in"].as_u64(), r["test_code"].as_bool()), (Some(reached), Some(fan_in), Some(false)), "{fqn}: {r}");
    }
    // a test — in a `cfg(test)` module or not — is test code, not surface
    assert_eq!((f("shop::cart::tests::adds_up")["test_code"].as_bool(), f("shop::pay::charges_once")["test_code"].as_bool()), (Some(true), Some(true)));
    // a method's module is the module its type lives in
    assert_eq!((f("shop::cart::Cart::add")["module"].as_str(), f("shop::cart::Cart::add")["module_path"].as_str()), (Some("shop::cart"), Some("shop::cart::Cart")));
    // each test: what it calls and names, what it reaches, the files those lie in
    let adds = row(&v["tests"], "test_name", "adds_up");
    assert_eq!((adds["calls_out"].as_u64(), adds["names"].as_u64(), adds["reached"].as_u64(), adds["is_heavy"].as_bool()), (Some(2), Some(2), Some(3), Some(false)));
    let files = |t: &Value| -> Vec<String> { t["files"].as_array().unwrap().iter().map(|i| v["files"][i.as_u64().unwrap() as usize]["file"].as_str().unwrap().to_string()).collect() };
    assert_eq!(files(adds), s(&["src/cart.rs"]));
    let charges = row(&v["tests"], "test_name", "charges_once");
    assert_eq!((charges["reached"].as_u64(), files(charges), charges.get("is_heavy").is_none()), (Some(3), s(&["src/pay.rs"]), true), "no `ignored` value in the log: left out, not false");
    assert_eq!(v["state"], "complete", "{v}");
    assert!(notes(&v).contains("lower bound"));
    // a scope with no test: nothing is reachable, and that is a GAP, not a measurement
    let web = ask("Knowledge.TestReach", json!({ "repo": WEB }));
    assert_eq!((web["tests_total"].as_u64(), web["test_reachable"].as_u64(), web["state"].as_str()), (Some(0), Some(0), Some("partial")));
    assert_eq!(missing(&web), s(&["tests"]));
}

#[test]
fn a_snapshot_diff_by_repo_is_its_last_two_consumed_commits_per_crate() {
    // shop: seq 1 → 2 moved spans only — no node changed (a fact)
    let v = ask("Coderoom.SnapshotDiff", json!({ "repo": SHOP }));
    assert_eq!((v["from"].as_str(), v["to"].as_str(), v["state"].as_str(), v["added_nodes"].as_u64()), (Some("shop@1"), Some("shop@2"), Some("empty_fact"), Some(0)));
    assert_eq!(v["by_crate"], json!({ "crates": [], "crates_added": [], "crates_removed": [] }));
    assert_eq!((v["room_from"]["repos"][0]["seq"].as_u64(), v["room_to"]["repos"][0]["seq"].as_u64(), v["room_to"]["nodes"].as_u64()), (Some(1), Some(2), Some(22)));
    // web: ONE consumed commit — compared with the empty state before it, and said
    let v = ask("Coderoom.SnapshotDiff", json!({ "repo": WEB }));
    assert_eq!((v["from"].as_str(), v["to"].as_str(), v["added_nodes"].as_u64(), v["room_from"]["nodes"].as_u64()), (Some("web@0"), Some("web@1"), Some(3), Some(0)));
    assert!(notes(&v).contains("`web` has ONE consumed commit (seq 1)"), "{}", notes(&v));
    assert_eq!(v["by_crate"]["crates_added"], json!(["shop@0.1.0", "web@0.2.0"]));
    let web_delta = row(&v["by_crate"]["crates"], "crate", "web@0.2.0");
    assert_eq!((web_delta["symbols_added"].as_u64(), web_delta["nodes_added"].as_u64(), web_delta["symbols_removed"].as_u64()), (Some(1), Some(2), Some(0)));
    // the two explicit states still work as before
    let v = ask("Coderoom.SnapshotDiff", json!({ "snap_a": "shop@1", "snap_b": "shop@2" }));
    assert_eq!(v["state"], "empty_fact");
}

/// The wire door: ONE JSON object per question, always with `state` and
/// `surface`; a refusal is a body, by state, with its sentence.
#[test]
fn the_wire_door_answers_every_outcome_as_a_body_with_a_state() {
    use super::super::door;
    let v = door("Viz.CrateGraph", &shop(), "");
    assert_eq!((v["surface"].as_str(), v["state"].as_str(), v.get("refused").is_none()), (Some("Viz.CrateGraph"), Some("complete"), true));
    assert_eq!(door("Viz.CallGraph", &shop(), r#"{"repo":"shop","limit":1}"#)["edges"].as_array().unwrap().len(), 1, "the request is the JSON text");
    for (surface, reach, params, state) in [
        ("Coderoom.Compat", shop(), "{}", "not_wired"),
        ("Coderoom.WhatBreaks", shop(), "", "not_wired"),
        ("Viz.CrateGraph", Reach::none(), "{}", "no_room"),
        ("Viz.CrateGraph", Reach::room_only(&fixture::unconsumed().handle), "{}", "not_consumed"),
        ("Knowledge.Callers", shop(), r#"{"repo":"nobody","name":"open"}"#, "not_consumed"),
        ("Viz.Nope", shop(), "{}", "invalid_argument"),
        ("Viz.CrateGraph", shop(), "{not json", "invalid_argument"),
    ] {
        let v = door(surface, &reach, params);
        assert_eq!((v["state"].as_str(), v["refused"].as_bool(), v["surface"].as_str()), (Some(state), Some(true), Some(surface)), "{surface} {params}: {v}");
        assert!(v["note"].as_str().is_some_and(|n| !n.trim().is_empty()), "{surface}: a refusal without its sentence: {v}");
    }
    // an answer that is a fixed list has no gap to name
    assert_eq!(door("Mimir.SqlTemplate", &Reach::none(), r#"{"template":""}"#)["state"], "complete");
}

// ------------------------------------------------------------- table access (TOUCHES_TABLE)

fn depot() -> Reach<'static> {
    Reach::room_only(&fixture::depot().handle)
}

fn ask_depot(surface: &str, params: Value) -> Value {
    answer(surface, &depot(), &params).unwrap_or_else(|r| panic!("{surface}: refused [{}] {}", r.state, r.note))
}

/// The table lineage: who reads / writes one table, site by site, and who
/// reaches them — from the room's TOUCHES_TABLE edges.
#[test]
fn the_table_lineage_is_the_rooms_touches_table_edges() {
    use fixture::depot::{DEPOT, TILL};
    let v = ask_depot("Mimir.SqlTemplate", json!({ "template": "table-access-lineage", "params": { "table": "stock_levels" } }));
    assert_eq!(v["state"], "complete", "{v}");
    // one row per site: the reader, the writer's two sites, and the OTHER repo's reader
    let rows: Vec<(String, String, String, u64)> =
        v["rows"].as_array().unwrap().iter().map(|r| (r["caller_fn"].as_str().unwrap().to_string(), r["access"].as_str().unwrap().to_string(), r["repo"].as_str().unwrap().to_string(), r["line"].as_u64().unwrap())).collect();
    assert_eq!(
        rows,
        vec![
            ("depot::store::append_stock".into(), "write".into(), DEPOT.into(), 21),
            ("depot::store::append_stock".into(), "write".into(), DEPOT.into(), 24),
            ("depot::store::query_stock".into(), "read".into(), DEPOT.into(), 11),
            ("till::sale".into(), "read".into(), TILL.into(), 7),
        ],
        "two repos meet at one table node"
    );
    assert_eq!((v["readers"].as_u64(), v["writers"].as_u64(), v["sites"].as_u64()), (Some(2), Some(1), Some(4)), "{v}");
    assert_eq!(v["rows"][0]["file"], "src/store.rs");
    // … and everything that reaches a toucher along CALLS
    assert_eq!(strs(&v["reached_from"]), s(&["depot::core::plan", "depot::svc::StockSvc::list", "depot::svc::StockSvc::put"]));
    assert_eq!(v["reached_from_total"], 3);
    // the runtime-named sites are said beside every answer, never folded into a table
    assert!(notes(&v).contains("2 site(s) in 1 fn(s) touch a table whose name is not known at compile time") && notes(&v).contains("depot::store::preview"), "{}", notes(&v));

    // one repo's code only: the other repo's reader is not listed
    let one = ask_depot("Mimir.SqlTemplate", json!({ "template": "table-access-lineage", "params": { "table": "stock_levels", "repo": DEPOT } }));
    assert_eq!(col(&one["rows"], "caller_fn"), s(&["depot::store::append_stock", "depot::store::append_stock", "depot::store::query_stock"]));
    // read AND write by one fn: in both counts
    let moves = ask_depot("Mimir.SqlTemplate", json!({ "template": "table-access-lineage", "params": { "table": "stock_moves" } }));
    assert_eq!((moves["readers"].as_u64(), moves["writers"].as_u64()), (Some(1), Some(2)), "{moves}");
    assert_eq!(moves["rows"].as_array().unwrap().iter().find(|r| r["caller_fn"] == "depot::store::audit").unwrap()["access"], "both");

    // the sites with no table name are their own answer
    let u = ask_depot("Mimir.SqlTemplate", json!({ "template": "table-access-lineage", "params": { "table": "<unresolved>" } }));
    assert_eq!(u["rows"].as_array().unwrap().iter().map(|r| r["line"].as_u64().unwrap()).collect::<Vec<_>>(), [51, 53]);
    assert_eq!(strs(&u["reached_from"]), s(&["depot::svc::StockSvc::browse"]));

    // a name no fn touches: invalid, and the answer names the tables there are
    let r = refused("Mimir.SqlTemplate", &depot(), json!({ "template": "table-access-lineage", "params": { "table": "nope" } }));
    assert_eq!(r.state, State::InvalidArgument);
    assert!(r.note.contains("stock_levels, stock_moves") && r.note.contains("2 more site(s) name their table at runtime"), "{}", r.note);
    assert_eq!(refused("Mimir.SqlTemplate", &depot(), json!({ "template": "table-access-lineage", "params": {} })).state, State::InvalidArgument);
}

/// The board gets its Table nodes and reads / writes edges from the room, and
/// every 🚇 line its terminus: the table nearest to the gRPC handler.
#[test]
fn the_board_has_table_nodes_and_the_metro_lines_end_at_the_nearest_table() {
    let (payload, ev) = arch_payload(&depot()).unwrap();
    let tables: Vec<&str> = payload.graph.nodes.iter().filter(|n| n.kind == arch::NodeKind::Table).map(|n| n.id.as_str()).collect();
    assert_eq!(tables, ["table:stock_levels", "table:stock_moves"], "one node per table NAME; the runtime-named sites are no node");
    let into = |table: &str| -> Vec<(String, String)> {
        payload.graph.edges.iter().filter(|e| e.to == table).map(|e| (e.from.clone(), e.kind.as_str().to_string())).collect()
    };
    assert_eq!(into("table:stock_levels"), vec![("corefn:depot::store".into(), "reads".into()), ("corefn:depot::store".into(), "writes".into()), ("corefn:till".into(), "reads".into())]);
    assert_eq!(into("table:stock_moves"), vec![("corefn:depot::store".into(), "reads".into()), ("corefn:depot::store".into(), "writes".into())]);
    // the handlers are gRPC nodes, and they reach the tables through the store
    assert!(payload.graph.nodes.iter().any(|n| n.id == "grpc:Stock.Put"), "{:?}", payload.graph.nodes);
    assert!(!ev.missing.iter().any(|m| m.input == "TOUCHES_TABLE edges"), "{ev}");
    assert!(ev.notes.iter().any(|n| n.contains("touch a table whose name is not known at compile time")), "{ev}");

    // the termini: nearest table(s) per handler, by name
    let of = |handler: &str| -> Vec<&str> { payload.access.iter().filter(|(h, _)| h == handler).map(|(_, t)| t.as_str()).collect() };
    assert_eq!(of("depot::svc::StockSvc::put"), ["stock_levels", "stock_moves"], "two tables at the same distance (put → store fn → table)");
    assert_eq!(of("depot::svc::StockSvc::list"), ["stock_levels"], "through core::plan: one hop further, still the nearest");
    assert_eq!(of("depot::svc::StockSvc::browse"), ["<unresolved>"], "its only table is named at runtime: the terminus says so");
    assert!(of("depot::svc::StockSvc::ping").is_empty(), "reaches no table: a placeholder terminus, not an invented one");
    assert!(ev.notes.iter().any(|n| n.contains("3 of 4 gRPC handler(s) reach a warehouse table")), "{ev}");

    // the wire carries them, and the trace of a handler ends in its table
    let v = ask_depot("Viz.Architecture", json!({ "workspace": "" }));
    assert_eq!(v["access"].as_array().unwrap().len(), 4);
    let t = ask_depot("Arch.Trace", json!({ "repo": fixture::depot::DEPOT, "entrypoint": "Stock.List" }));
    assert!(t["graph"]["nodes"].as_array().unwrap().iter().any(|n| n["id"] == "table:stock_levels"), "{t}");
}

/// The producer ran and no fn touches a table: no Table node is a FACT (the
/// lake was written with the `access` column), and nothing is invented.
#[test]
fn code_that_touches_no_table_has_no_table_node_and_says_it_is_a_fact() {
    let reach = Reach::room_only(&fixture::depot_untouched().handle);
    let (payload, ev) = arch_payload(&reach).unwrap();
    assert!(payload.graph.nodes.iter().all(|n| n.kind != arch::NodeKind::Table));
    assert!(payload.access.is_empty());
    assert!(!ev.missing.iter().any(|m| m.input == "TOUCHES_TABLE edges"), "{ev}");
    let r = refused("Mimir.SqlTemplate", &reach, json!({ "template": "table-access-lineage", "params": { "table": "stock_levels" } }));
    assert_eq!(r.state, State::InvalidArgument);
    assert!(r.note.contains("0 table(s)"), "{}", r.note);
}

/// **The real-repo instrument for the table readers.** Against a lake a
/// consumer wrote for a real repo: the lineage of one table, the board's
/// Table nodes and the metro termini, with timings. `#[ignore]`d — it reads a
/// lake outside the tree:
///
/// ```text
/// MIMIR_PROOF_BUILDS=<builds dir holding mimir_v2/lake> [MIMIR_PROOF_TABLE=<table>] \
///   cargo test --lib real_lake_table_readers -- --ignored --nocapture
/// ```
#[test]
#[ignore = "reads a real lake: set MIMIR_PROOF_BUILDS"]
fn real_lake_table_readers() {
    let builds = std::path::PathBuf::from(std::env::var("MIMIR_PROOF_BUILDS").expect("MIMIR_PROOF_BUILDS"));
    let table = std::env::var("MIMIR_PROOF_TABLE").unwrap_or_else(|_| "bench_runs".to_string());
    let room = crate::code_room::CodeRoom::new("proof", &builds);
    let reach = Reach::room_only(&room);
    for t in [table.as_str(), mimir_schema::TABLE_UNRESOLVED, "no_such_table"] {
        let at = std::time::Instant::now();
        match answer("Mimir.SqlTemplate", &reach, &json!({ "template": "table-access-lineage", "params": { "table": t } })) {
            Ok(v) => {
                println!("\n=== lineage of `{t}`: state {} · {} row(s) · readers {} writers {} sites {} · reached from {} · {} ms", v["state"], v["rows"].as_array().map_or(0, Vec::len), v["readers"], v["writers"], v["sites"], v["reached_from_total"], at.elapsed().as_millis());
                for r in v["rows"].as_array().into_iter().flatten().take(12) {
                    println!("    {} {} {}:{}", r["access"].as_str().unwrap_or("?"), r["caller_fn"].as_str().unwrap_or("?"), r["file"].as_str().unwrap_or("?"), r["line"]);
                }
                println!("    notes: {}", notes(&v));
            }
            Err(r) => println!("\n=== lineage of `{t}`: refused [{}] {} ({} ms)", r.state, r.note, at.elapsed().as_millis()),
        }
    }
    let at = std::time::Instant::now();
    let (payload, ev) = arch_payload(&reach).unwrap();
    let tables = payload.graph.nodes.iter().filter(|n| n.kind == arch::NodeKind::Table).count();
    let into_tables = payload.graph.edges.iter().filter(|e| e.to.starts_with("table:")).count();
    let handlers: BTreeSet<&str> = payload.access.iter().map(|(h, _)| h.as_str()).collect();
    println!(
        "\n=== board: {} nodes ({tables} Table), {} edges ({into_tables} reads / writes into a table) · metro termini: {} pair(s) for {} handler(s) · {} ms",
        payload.graph.nodes.len(),
        payload.graph.edges.len(),
        payload.access.len(),
        handlers.len(),
        at.elapsed().as_millis()
    );
    for (h, t) in payload.access.iter().take(15) {
        println!("    {h}  →  {t}");
    }
    println!("    evidence: {ev}");
}

// ------------------------------------------------------------- the code room in 3-D

/// `Viz.CodeRoom3D`: every fn of the repo a block with its body's span, a
/// function it calls elsewhere a block of its own, and one site per call —
/// `[caller, callee, line]` — at the line the call is written on.
#[test]
fn the_code_room_in_3d_is_blocks_with_spans_and_a_site_per_call_at_its_line() {
    let v = ask("Viz.CodeRoom3D", json!({ "repo": SHOP }));
    let fns = v["fns"].as_array().unwrap();
    let by_id = |id: &str| fns.iter().position(|f| f["id"] == id).unwrap_or_else(|| panic!("no block {id} in {v}"));
    let by_name = |name: &str| fns.iter().position(|f| f["name"] == name).unwrap_or_else(|| panic!("no block named {name} in {v}"));
    let checkout = &fns[by_id("shop::checkout")];
    assert_eq!(
        (checkout["home"].as_bool(), checkout["file"].as_str(), checkout["start_line"].as_u64(), checkout["end_line"].as_u64()),
        (Some(true), Some("src/lib.rs"), Some(10), Some(20)),
        "{checkout}"
    );
    let lines = |from: usize, to: usize| -> Vec<u64> {
        let mut l: Vec<u64> = v["sites"].as_array().unwrap().iter().filter(|s| s[0] == json!(from) && s[1] == json!(to)).filter_map(|s| s[2].as_u64()).collect();
        l.sort_unstable();
        l
    };
    let (checkout, charge, total) = (by_id("shop::checkout"), by_id("shop::pay::charge"), by_name("total"));
    assert_eq!(lines(checkout, charge), vec![14, 15, 18], "one light per call site, at its line");
    assert_eq!(lines(checkout, total), vec![12]);
    // a function called in a dependency is a block too, not one of the repo's own
    let send = by_id("stripe::Client::send");
    assert_eq!(fns[send]["home"], false, "{}", fns[send]);
    assert!(v["sites"].as_array().unwrap().iter().any(|s| s[0] == json!(charge) && s[1] == json!(send)), "charge → send is drawn");
    assert_eq!(v["state"], "complete", "{v}");
    assert_eq!(v["room"]["workspace"], "ws", "the answer names the room it was read from");
    // a cap is said: the blocks that fit, the calls that did not, the total
    let cut = ask("Viz.CodeRoom3D", json!({ "repo": SHOP, "limit": 2 }));
    assert_eq!(cut["fns"].as_array().unwrap().len(), 2);
    assert!(cut["dropped_calls"].as_u64().unwrap() > 0, "{cut}");
    assert_eq!(cut["evidence"]["capped"]["total"], v["total_home_fns"], "{cut}");
}

/// **The 3-D room grows call trees**: blocks come along the calls — from the
/// function that calls the most others, or from `root` — so a capped room
/// still has its beams. RED WHEN REVERTED (the room's first blocks): with a
/// cap of 2 the two blocks were not caller and callee, no site was drawn.
#[test]
fn the_code_room_in_3d_grows_call_trees_from_a_root_or_the_busiest_caller() {
    let two = ask("Viz.CodeRoom3D", json!({ "repo": SHOP, "limit": 2 }));
    let fns = two["fns"].as_array().unwrap();
    assert_eq!(fns.len(), 2);
    assert!(
        two["sites"].as_array().unwrap().iter().any(|s| s[0] == json!(0) && s[1] == json!(1)),
        "the second block is one the first calls, so a beam is drawn: {two}"
    );
    let from = ask("Viz.CodeRoom3D", json!({ "repo": SHOP, "root": "charge", "limit": 2 }));
    let f = from["fns"].as_array().unwrap();
    assert_eq!(f[0]["id"], "shop::pay::charge", "the root first: {from}");
    assert!(from["sites"].as_array().unwrap().iter().any(|s| s[0] == json!(0) && s[1] == json!(1)), "then a function it calls: {from}");
    assert_eq!(from["root"], "charge");
    assert!(from["evidence"]["notes"].to_string().contains("from `charge`"), "{from}");
    let none = refused("Viz.CodeRoom3D", &shop(), json!({ "repo": SHOP, "root": "no_such_fn" }));
    assert_eq!(none.state, State::InvalidArgument, "{none}");
}

// ------------------------------------------------------------- the binary half

/// `Viz.Binary` is the binary half of the room: per artifact what it links,
/// and for the artifact asked (default: the one linking the most bytes) its
/// bytes by crate, its largest symbols and its ledger rows per release.
#[test]
fn the_binary_half_is_each_artifacts_bytes_by_crate_and_symbol() {
    // the whole workspace: `web` was consumed without the binary stream — a lower
    // bound, and the evidence names the gap
    let v = ask("Viz.Binary", json!({}));
    assert_eq!(v["state"], "partial", "{v}");
    assert_eq!(missing(&v), ["binary stream"], "{v}");
    let v = ask("Viz.Binary", json!({ "repo": SHOP }));
    assert_eq!(v["state"], "complete", "{v}");
    assert_eq!(v["artifact"], ARTIFACT, "{v}");
    let arts = v["artifacts"].as_array().unwrap();
    assert_eq!(arts.len(), 1, "{v}");
    // checkout 120 B · charge 300 B · its closure 40 B; `write` is an import
    assert_eq!((arts[0]["binary"].as_str(), arts[0]["symbols"].as_u64(), arts[0]["bytes"].as_u64(), arts[0]["imports"].as_u64()), (Some("shop"), Some(3), Some(460), Some(1)), "{v}");
    assert_eq!(v["crates"], json!([{ "crate": "shop", "bytes": 460, "symbols": 3 }]), "{v}");
    let syms: Vec<(String, u64)> = v["symbols"].as_array().unwrap().iter().map(|s| (s["mangled"].as_str().unwrap().to_string(), s["bytes"].as_u64().unwrap())).collect();
    assert_eq!(syms, [("_Rcharge".to_string(), 300), ("_Rcheckout".to_string(), 120), ("_Rcharge_closure0".to_string(), 40)]);
    assert_eq!(v["symbols"][0]["symbol"], "shop::pay::charge", "the demangled name is the one shown");
    assert!(!v["history"].as_array().unwrap().is_empty(), "the artifact's ledger rows: {v}");
    assert!(notes(&v).contains("hardening"), "says hardening is not in the binary layer: {}", notes(&v));
    assert!(v["room"]["workspace"].is_string(), "names the room: {v}");
    // a cap says so
    let v = ask("Viz.Binary", json!({ "artifact": "shop", "limit": 1 }));
    assert_eq!((v["symbols"].as_array().unwrap().len(), v["total_symbols"].as_u64()), (1, Some(3)));
    assert_eq!(v["evidence"]["capped"], json!({ "shown": 1, "total": 3 }));
    // an artifact the room does not link is a wrong request, naming what is linked
    let r = refused("Viz.Binary", &shop(), json!({ "artifact": "nope" }));
    assert_eq!(r.state, State::InvalidArgument);
    assert!(r.note.contains(ARTIFACT), "{}", r.note);
    // a repo consumed WITHOUT the binary layer: its state, never an empty binary
    let r = refused("Viz.Binary", &shop(), json!({ "repo": WEB }));
    assert_eq!(r.state, State::NotConsumed, "{}", r.note);
    assert!(r.note.contains("binary stream"), "{}", r.note);
}