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/panes.rs

//! The readers a THIN client's panes ask through the wire door
//! (`CodeRoom.Answer`, [`super::super::door`]): the crate graph, the
//! function tier, symbol rows, the source of one item, and what the tests of
//! a repo reach.
//!
//! A pane only draws. So everything a pane would otherwise have to compute —
//! a quotient, a walk, a join of a node with its file — is computed HERE, and
//! every answer says which room it was read from ([`identity`]): workspace,
//! repo@seq with the commit, node and edge counts. A person can put the
//! numbers on the screen beside the same question asked of the server.

use std::collections::{BTreeMap, BTreeSet};

use mimir_room::{EdgeSel, GroupBy, MaskSpec, Room, Scope};
use mimir_schema::{EdgeKind, Origin, kind as nk};
use serde_json::{Value, json};

use super::{
    LOWER_BOUND, Paths, obj, SYMBOL_KINDS, absorb, envelope, impl_traits, internal, invalid, limit_of, miss, note, open, open_in, resolve, settle, symbol_json_of, symbol_nodes,
    symbol_row, text,
};
use crate::code_room::{CodeRoom, Reach, Refusal, State};
use crate::mimir_lens::room_feed::cfg_requires_test;

/// Edges of the call-graph pane when the request names no cap.
const CALL_GRAPH_CAP: usize = 2_000;
/// Fns of ONE crate a function-tier page holds when the request names no size.
const FUNCTION_TIER_PAGE: usize = 2_000;
/// Fns a function-tier page holds at most.
const FUNCTION_TIER_PAGE_MAX: usize = 20_000;
/// Fns per crate a function-tier SUMMARY previews at most (`per_crate`).
const FUNCTION_TIER_PREVIEW_MAX: usize = 500;
/// Blocks `Viz.CodeRoom3D` hands out: what a 3-D room can draw and a person
/// can still fly through. Past it the answer says how many it left out.
const CODE_ROOM_3D_CAP: usize = 4_000;
/// Call sites `Viz.CodeRoom3D` hands out (each `[caller, callee, line]`).
const CODE_ROOM_3D_SITES_CAP: usize = 60_000;
/// Symbol rows of a listing when the request names no cap.
const SYMBOLS_CAP: usize = 2_000;
/// Tests whose own reach is walked (one walk each).
const TEST_WALK_CAP: usize = 2_000;
/// Lines of one item the source reader returns when the request names no cap.
const SOURCE_LINES: usize = 400;
/// Lines the source reader returns at most.
const SOURCE_LINES_MAX: usize = 4_000;

/// Which room an answer was read from — the line a pane prints so its
/// numbers can be compared with the server's.
pub fn identity(handle: &CodeRoom, room: &Room) -> Value {
    let st = room.stats();
    let sc = room.scope();
    let edges: BTreeMap<String, u64> = st.edges.iter().map(|(k, n)| (k.as_str().to_string(), *n)).collect();
    json!({
        "workspace": handle.workspace(),
        "scope": sc.to_string(),
        "universe": sc.universe,
        "repos": sc.repos.iter().map(|(r, seq)| json!({ "repo": r, "seq": seq, "sha": sc.offset_shas.get(r) })).collect::<Vec<_>>(),
        "nodes": st.nodes,
        "edges_total": edges.values().sum::<u64>(),
        "edges": edges,
        "files": st.files,
        "tests": st.tests,
    })
}

fn with_identity(mut body: Value, handle: &CodeRoom, room: &Room) -> Value {
    if let Some(o) = body.as_object_mut() {
        o.insert("room".into(), identity(handle, room));
    }
    body
}

fn flag(p: &Value, key: &str) -> bool {
    p.get(key).and_then(Value::as_bool).unwrap_or(false)
}

/// The room of every consumed repo, with the dependency ring folded in when
/// `ring` — or the state that says why there is none.
fn open_ring(handle: &CodeRoom, ring: bool) -> Result<Room, Refusal> {
    if !ring {
        return open_in(handle, "");
    }
    let room = handle.room(&Scope::current().with_universe(true))?;
    if room.scope().repos.is_empty() {
        return Err(Refusal::new(
            State::NotConsumed,
            format!("code room of `{}`: no repo has a consumer offset yet — nothing of this workspace was consumed", handle.workspace()),
        ));
    }
    Ok(room)
}

fn repos_of(repo: &str) -> Vec<String> {
    if repo.is_empty() { vec![] } else { vec![repo.to_string()] }
}

// ------------------------------------------------------------------ crate graph

/// `Viz.CrateGraph`: the room collapsed by crate. One row per `name@version`
/// the room holds a node of, and per pair of crates what joins them:
/// `depends_on` (the manifest edge), `calls` (item → item CALLS edges, with
/// their `call_sites`), `uses_type`. `universe` folds the dependency ring in
/// (its crates then have their own items; without it they are the reference
/// stubs the workspace's own code points at).
pub fn crate_graph(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let handle = reach.code_room()?;
    let room = open_ring(handle, flag(p, "universe"))?;
    let by = |kind: EdgeKind| room.quotient(GroupBy::Crate, &[kind], None).map_err(internal);
    let (dep, calls, types) = (by(EdgeKind::DependsOn)?, by(EdgeKind::Calls)?, by(EdgeKind::UsesType)?);
    // the three quotients group the same nodes the same way: their groups align
    let groups = &dep.value.groups;
    let mut crates: Vec<Value> = Vec::with_capacity(groups.len());
    let mut local_of_repo: BTreeMap<String, Vec<String>> = room.scope().repos.keys().map(|r| (r.clone(), Vec::new())).collect();
    for (i, g) in groups.iter().enumerate() {
        let (name, version) = g.key.rsplit_once('@').unwrap_or((g.key.as_str(), ""));
        let own = g.node.map(|n| room.node(n));
        let local = own.as_ref().is_some_and(|v| v.defined && v.origin == Some(Origin::Local));
        let repo = own.as_ref().and_then(|v| v.repo);
        if let (true, Some(r)) = (local, repo)
            && let Some(list) = local_of_repo.get_mut(r)
        {
            list.push(g.key.clone());
        }
        let count = |kinds: &[&str]| g.node_kinds.iter().filter(|(k, _)| kinds.contains(&k.as_str())).map(|(_, n)| *n).sum::<u64>();
        crates.push(json!({
            "id": g.key,
            "name": name,
            "version": version,
            // the consumed repo that DEFINES the crate; none for a dependency
            "repo": repo.filter(|_| local),
            "local": local,
            "nodes": g.nodes,
            "symbols": count(&SYMBOL_KINDS),
            "fns": count(&[nk::FN, nk::METHOD]),
            "files": g.files,
            "calls_inside": calls.value.groups.get(i).map_or(0, |c| c.internal),
        }));
    }
    #[derive(Default)]
    struct Join {
        depends_on: u64,
        calls: u64,
        call_sites: u64,
        uses_type: u64,
    }
    let mut joins: BTreeMap<(usize, usize), Join> = BTreeMap::new();
    for e in &dep.value.edges {
        joins.entry((e.from, e.to)).or_default().depends_on += e.edges;
    }
    for e in &calls.value.edges {
        let j = joins.entry((e.from, e.to)).or_default();
        j.calls += e.edges;
        j.call_sites += e.sites;
    }
    for e in &types.value.edges {
        joins.entry((e.from, e.to)).or_default().uses_type += e.edges;
    }
    let edges: Vec<Value> = joins
        .iter()
        .map(|((f, t), j)| json!({ "from": groups[*f].key, "to": groups[*t].key, "depends_on": j.depends_on, "calls": j.calls, "call_sites": j.call_sites, "uses_type": j.uses_type }))
        .collect();
    // repo → repo, by what their crates say of each other
    let repo_of: Vec<Option<&str>> = groups
        .iter()
        .map(|g| g.node.map(|n| room.node(n)).filter(|v| v.defined && v.origin == Some(Origin::Local)).and_then(|v| v.repo))
        .collect();
    let mut repo_joins: BTreeMap<(&str, &str), (u64, u64, BTreeSet<&str>)> = BTreeMap::new();
    for ((f, t), j) in &joins {
        let (Some(a), Some(b)) = (repo_of[*f], repo_of[*t]) else { continue };
        if a == b {
            continue;
        }
        let slot = repo_joins.entry((a, b)).or_default();
        slot.0 += j.depends_on;
        slot.1 += j.calls;
        if j.depends_on > 0 {
            slot.2.insert(groups[*t].label.as_str());
        }
    }
    let repo_edges: Vec<Value> = repo_joins.iter().map(|((a, b), (d, c, via))| json!({ "from": a, "to": b, "depends_on": d, "calls": c, "via": via })).collect();
    // what each repo's own crates depend on, by crate name (its own crates included)
    let mut consumes: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new();
    for ((f, t), j) in &joins {
        if let (Some(r), true) = (repo_of[*f], j.depends_on > 0) {
            consumes.entry(r).or_default().insert(groups[*t].label.as_str());
        }
    }
    let repos: Vec<Value> = room
        .scope()
        .repos
        .iter()
        .map(|(r, seq)| json!({ "repo": r, "seq": seq, "sha": room.scope().offset_shas.get(r), "crates": local_of_repo.get(r), "consumes": consumes.get(r.as_str()).cloned().unwrap_or_default() }))
        .collect();
    let mut ev = dep.evidence;
    absorb(&mut ev, &calls.evidence);
    absorb(&mut ev, &types.evidence);
    ev.query = format!("crate graph ({} ring)", if room.scope().universe { "with the dependency" } else { "without the dependency" });
    note(
        &mut ev,
        "a crate = `name@version` of the nodes the room holds; `local` = a crate a consumed repo defines. depends_on = DEPENDS_ON edges between the two crates; \
         calls = CALLS edges from an item of the one to an item of the other, call_sites = their sites; uses_type likewise",
    );
    if !room.scope().universe {
        note(&mut ev, "ring off: a dependency crate is here only as the reference stubs the workspace's own code points at — its `nodes` are those stubs, not its items");
    }
    note(&mut ev, LOWER_BOUND);
    settle(&mut ev, crates.is_empty());
    Ok(with_identity(
        envelope(obj([("crates", Value::Array(crates)), ("edges", Value::Array(edges)), ("repos", Value::Array(repos)), ("repo_edges", Value::Array(repo_edges))]), &ev),
        handle,
        &room,
    ))
}

// ------------------------------------------------------------------ functions

/// `Viz.CallGraph`: [`super::call_graph`] with the room it was read from.
pub fn call_graph_answer(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let (graph, ev) = super::call_graph(reach, repo, limit_of(p, CALL_GRAPH_CAP))?;
    let handle = reach.code_room()?;
    let room = open(reach, repo)?;
    Ok(with_identity(envelope(graph, &ev), handle, &room))
}

/// `Viz.FunctionTier`: per repo, per local crate, its fns and methods and the
/// CALLS edges among them — the function tier of a navigator, in its shape.
/// Calls that leave the crate are not here (the crate graph counts them).
///
/// **A summary by default.** The whole room's fns are far too many for one
/// answer (`nordisk`: 214 401 fns, 37 MB on the wire), so without `crate`
/// each crate carries its counts and at most `per_crate` fns (default 0, at
/// most [`FUNCTION_TIER_PREVIEW_MAX`]) — `id`, `name`, `is_test` only — with
/// the calls from them.
///
/// **One crate, a page at a time.** `crate` (with `repo` to pick one repo's)
/// drills in: `page` (from 0) of `page_size` fns (`limit` is the same;
/// default [`FUNCTION_TIER_PAGE`], at most [`FUNCTION_TIER_PAGE_MAX`]), each
/// with its full row, and the calls FROM them. Each crate says `offset`,
/// `page`, `pages` and `next_page` (null on the last), so the pages together
/// are the crate's fns and calls, each once.
///
/// A call is `[from, to, sites]`, indexes into the crate's WHOLE fn order (the
/// fn at `offset + i` of `fns` is index `offset + i`), so a `to` may name a
/// fn on another page.
pub fn function_tier(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let krate = text(p, "crate");
    let room = open(reach, repo)?;
    let handle = reach.code_room()?;
    let drill = !krate.is_empty();
    let num = |k: &str| p.get(k).and_then(Value::as_u64).map(|n| n as usize);
    let (lo, len) = if drill {
        let size = num("page_size").filter(|n| *n > 0).unwrap_or_else(|| limit_of(p, FUNCTION_TIER_PAGE)).min(FUNCTION_TIER_PAGE_MAX);
        (num("page").unwrap_or(0).saturating_mul(size), size)
    } else {
        (0, num("per_crate").unwrap_or(0).min(FUNCTION_TIER_PREVIEW_MAX))
    };
    let fns = room
        .mask(&MaskSpec { repos: repos_of(repo), origins: vec![Origin::Local], defined_only: true, node_kinds: vec![nk::FN.into(), nk::METHOD.into()], ..Default::default() })
        .map_err(internal)?;
    let found = room.edges(&EdgeSel::kinds(&[EdgeKind::Calls]).inside(&fns.value)).map_err(internal)?;
    struct Tier<'r> {
        version: &'r str,
        fns: Vec<Value>,
        /// every fn of the crate → its index in the crate's fn order
        index: BTreeMap<u64, usize>,
        calls: Vec<Value>,
        total_calls: u64,
    }
    let mut paths = Paths::new(&room);
    // keyed by the room's own strings: no allocation per fn or per call
    let mut tiers: BTreeMap<(&str, &str), Tier<'_>> = BTreeMap::new();
    let (mut total, mut shown) = (0usize, 0usize);
    for o in fns.value.ordinals() {
        let v = room.node(*o);
        let (Some(r), Some(k)) = (v.repo, v.krate) else { continue };
        if drill && k != krate {
            continue;
        }
        total += 1;
        let tier = tiers.entry((r, k)).or_insert_with(|| Tier { version: v.version.unwrap_or(""), fns: Vec::new(), index: BTreeMap::new(), calls: Vec::new(), total_calls: 0 });
        let at = tier.index.len();
        tier.index.insert(*o, at);
        if at < lo || at >= lo.saturating_add(len) {
            continue;
        }
        shown += 1;
        tier.fns.push(if drill {
            json!({ "id": paths.of(*o), "name": v.name, "moniker": v.moniker, "kind": v.kind, "file": v.file, "line": v.start_line, "is_test": v.is_test })
        } else {
            json!({ "id": paths.of(*o), "name": v.name, "is_test": v.is_test })
        });
    }
    let mut left_crate = 0u64;
    let mut calls_total = 0u64;
    for e in &found.value.edges {
        let (a, b) = (room.node(e.from), room.node(e.to));
        let (Some(r), Some(k)) = (a.repo, a.krate) else { continue };
        if b.krate != Some(k) || b.repo != Some(r) {
            left_crate += 1;
            continue;
        }
        let Some(tier) = tiers.get_mut(&(r, k)) else { continue };
        tier.total_calls += 1;
        calls_total += 1;
        if let (Some(&f), Some(&t)) = (tier.index.get(&e.from), tier.index.get(&e.to))
            && f >= lo
            && f < lo.saturating_add(len)
        {
            tier.calls.push(json!([f, t, e.count]));
        }
    }
    let mut by_repo: BTreeMap<&str, Vec<Value>> = BTreeMap::new();
    for ((r, k), t) in tiers {
        let n = t.index.len();
        let mut row = vec![
            ("crate", json!(k)),
            ("version", json!(t.version)),
            ("total_fns", json!(n)),
            ("total_calls", json!(t.total_calls)),
            ("offset", json!(lo.min(n))),
            ("fns", Value::Array(t.fns)),
            ("calls", Value::Array(t.calls)),
        ];
        if drill {
            let page = lo / len.max(1);
            let pages = n.div_ceil(len.max(1));
            row.extend([("page", json!(page)), ("page_size", json!(len)), ("pages", json!(pages)), ("next_page", if page + 1 < pages { json!(page + 1) } else { Value::Null })]);
        }
        by_repo.entry(r).or_default().push(obj_of(row));
    }
    let repos: Vec<Value> = by_repo.into_iter().map(|(r, crates)| obj([("repo", json!(r)), ("crates", Value::Array(crates))])).collect();
    let mut ev = fns.evidence;
    absorb(&mut ev, &found.evidence);
    ev.missing.retain(|m| !m.input.starts_with("node kind"));
    let whose = if repo.is_empty() { "every consumed repo".to_string() } else { repo.to_string() };
    ev.query = if drill { format!("function tier of crate `{krate}` in {whose}, fns {lo}..{}", lo.saturating_add(len)) } else { format!("function tier of {whose} (summary, {len} fn(s) a crate)") };
    if shown < total {
        ev.capped = Some(mimir_room::Capped { shown: shown as u64, total: total as u64 });
    }
    if !drill {
        note(&mut ev, "a summary: each crate's counts, and its first `per_crate` fns; ask `crate` (and `repo`) with `page` / `page_size` for a crate's fns");
    }
    note(&mut ev, &format!("fns and methods a consumed repo defines, per crate, and the CALLS edges among the fns of ONE crate; {left_crate} call edge(s) between local fns cross a crate and are in the crate graph, not here"));
    note(&mut ev, LOWER_BOUND);
    settle(&mut ev, total == 0);
    let mut body = vec![("mode", json!(if drill { "crate" } else { "summary" })), ("repos", Value::Array(repos)), ("total_fns", json!(total)), ("total_calls", json!(if drill { calls_total } else { found.value.total }))];
    if drill {
        body.push(("crate", json!(krate)));
    }
    Ok(with_identity(envelope(obj_of(body), &ev), handle, &room))
}

/// [`obj`] of a list whose length is not known at compile time.
fn obj_of(pairs: Vec<(&str, Value)>) -> Value {
    Value::Object(pairs.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}

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

/// One block of [`code_room_3d`]: a function with its body's span.
fn block(room: &Room, paths: &mut super::Paths<'_>, o: u64, home: bool) -> Value {
    let v = room.node(o);
    json!({
        "id": paths.of(o), "name": v.name, "moniker": v.moniker, "kind": v.kind,
        "repo": v.repo, "crate": v.krate, "version": v.version,
        "file": v.file, "start_line": v.start_line, "end_line": v.end_line,
        "home": home, "is_test": v.is_test,
    })
}

/// `Viz.CodeRoom3D`: the code as a room. Every fn and method a consumed repo
/// defines (one repo, or all of them) is a BLOCK with its body's span
/// (`home: true`); every function those call that lives elsewhere — another
/// repo, a dependency, std — is a block too (`home: false`); and every CALL
/// SITE is `[caller, callee, line]`, indexes into `fns`, with the line of the
/// call in the caller's file (`null` where the room holds no site span). What
/// the dwarves "Code room" view draws: a light per site on its block at its
/// line, a beam from it to the block it calls.
///
/// **Call trees, not the room's order.** The blocks are grown breadth-first
/// along the calls: from `root` (a function's name or the tail of its path,
/// e.g. `consume` or `monitor::fetch`) when given, else from the functions
/// that call the most others. Each block brings the functions it calls, then
/// theirs, until the cap — so a beam lands on a pillar that is in the room.
/// (Taking the room's first blocks drew 1 500 unrelated pillars and dropped
/// 1.19 M of the calls, owner 2026-10-15: "functions and their line to sub
/// functions".)
///
/// Capped (`limit`, default 4 000 blocks; 60 000 sites); a call whose either
/// end did not fit is counted in `dropped_calls`, never drawn half.
pub fn code_room_3d(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let root = text(p, "root");
    let room = open(reach, repo)?;
    let handle = reach.code_room()?;
    let cap = limit_of(p, CODE_ROOM_3D_CAP);
    let scope = room
        .mask(&MaskSpec { repos: repos_of(repo), origins: vec![Origin::Local], defined_only: true, node_kinds: vec![nk::FN.into(), nk::METHOD.into()], ..Default::default() })
        .map_err(internal)?;
    let calls = room.edges(&EdgeSel { kinds: vec![EdgeKind::Calls], from: Some(&scope.value), to: None, cap: None, heaviest_first: false }).map_err(internal)?;
    let mut paths = super::Paths::new(&room);
    let total_home = scope.value.len();
    // who each function of the scope calls (distinct callees, in the room's order)
    let mut callees: BTreeMap<u64, Vec<u64>> = BTreeMap::new();
    for e in &calls.value.edges {
        let to = callees.entry(e.from).or_default();
        if to.last() != Some(&e.to) && !to.contains(&e.to) {
            to.push(e.to);
        }
    }
    let seeds: Vec<u64> = if root.is_empty() {
        let mut by_fanout: Vec<(usize, u64)> = callees.iter().map(|(f, t)| (t.len(), *f)).collect();
        by_fanout.sort_by(|a, b| b.0.cmp(&a.0).then(a.1.cmp(&b.1)));
        by_fanout.into_iter().map(|(_, f)| f).collect()
    } else {
        let tail = format!("::{root}");
        scope
            .value
            .ordinals()
            .iter()
            .copied()
            .filter(|o| {
                let id = paths.of(*o);
                room.node(*o).name == Some(root) || id == root || id.ends_with(&tail)
            })
            .collect()
    };
    if !root.is_empty() && seeds.is_empty() {
        return Err(Refusal::new(State::InvalidArgument, format!("no fn or method named `{root}` in {}", if repo.is_empty() { "the consumed repos" } else { repo })));
    }
    let mut index: BTreeMap<u64, usize> = BTreeMap::new();
    let mut fns: Vec<Value> = Vec::new();
    let mut queue: std::collections::VecDeque<u64> = std::collections::VecDeque::new();
    'grow: for seed in seeds {
        if fns.len() >= cap {
            break;
        }
        if index.contains_key(&seed) {
            continue;
        }
        queue.push_back(seed);
        while let Some(o) = queue.pop_front() {
            if index.contains_key(&o) {
                continue;
            }
            if fns.len() >= cap {
                break 'grow;
            }
            index.insert(o, fns.len());
            fns.push(block(&room, &mut paths, o, scope.value.contains(o)));
            for &t in callees.get(&o).map(Vec::as_slice).unwrap_or(&[]) {
                if !index.contains_key(&t) {
                    queue.push_back(t);
                }
            }
        }
    }
    let (mut sites, mut dropped_calls, mut sites_seen) = (Vec::<Value>::new(), 0u64, 0u64);
    for e in &calls.value.edges {
        let (Some(&f), Some(&t)) = (index.get(&e.from), index.get(&e.to)) else {
            dropped_calls += 1;
            continue;
        };
        let at = room.sites(e.from, e.to, EdgeKind::Calls);
        let lines: Vec<Value> = if at.is_empty() { vec![Value::Null] } else { at.iter().map(|s| json!(s.start_line)).collect() };
        for line in lines {
            sites_seen += 1;
            if sites.len() < CODE_ROOM_3D_SITES_CAP {
                sites.push(json!([f, t, line]));
            }
        }
    }
    let home_shown = fns.iter().filter(|b| b["home"] == true).count();
    let mut ev = scope.evidence;
    absorb(&mut ev, &calls.evidence);
    ev.missing.retain(|m| !m.input.starts_with("node kind"));
    ev.query = format!(
        "code room in 3-D of {}{}",
        if repo.is_empty() { "every consumed repo" } else { repo },
        if root.is_empty() { String::new() } else { format!(", from `{root}`") }
    );
    if home_shown < total_home || (sites.len() as u64) < sites_seen {
        ev.capped = Some(mimir_room::Capped { shown: home_shown as u64, total: total_home as u64 });
    }
    note(
        &mut ev,
        &format!(
            "blocks grown along the calls from {}: each brings the functions it calls, then theirs. \
             a block = a fn or method with its body's span; `home` = defined by the repo(s) asked, else a function they call elsewhere (another repo, a dependency, std). \
             a site = [caller, callee, line of the call]; {dropped_calls} call(s) left out because an end did not fit the cap of {cap} block(s); {} of {sites_seen} site(s) shown",
            if root.is_empty() { "the functions that call the most others".to_string() } else { format!("`{root}`") },
            sites.len()
        ),
    );
    note(&mut ev, LOWER_BOUND);
    settle(&mut ev, fns.is_empty());
    Ok(with_identity(
        envelope(
            obj([
                ("fns", Value::Array(fns)),
                ("sites", Value::Array(sites)),
                ("root", json!(root)),
                ("total_home_fns", json!(total_home)),
                ("total_calls", json!(calls.value.total)),
                ("total_sites", json!(sites_seen)),
                ("dropped_calls", json!(dropped_calls)),
            ]),
            &ev,
        ),
        handle,
        &room,
    ))
}

// ------------------------------------------------------------------ symbols

/// `Knowledge.Symbols`: the symbol rows of a repo (of every consumed repo
/// when `repo` is empty), capped — a listing, where `Knowledge.SymbolLookup`
/// is a search. `kinds` narrows to node kinds (`fn`, `struct` …).
pub fn symbols(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let room = open(reach, repo)?;
    let handle = reach.code_room()?;
    let limit = limit_of(p, SYMBOLS_CAP);
    let kinds: BTreeSet<&str> = p.get("kinds").and_then(Value::as_array).map(|a| a.iter().filter_map(Value::as_str).collect()).unwrap_or_default();
    let nodes = symbol_nodes(&room, (!repo.is_empty()).then_some(repo))?;
    let traits = impl_traits(&room)?;
    let mut paths = Paths::new(&room);
    let mut rows: Vec<Value> = Vec::new();
    let mut total = 0usize;
    let mut by_kind: BTreeMap<String, u64> = BTreeMap::new();
    for o in nodes.ordinals() {
        let v = room.node(*o);
        let kind = v.kind.unwrap_or("");
        *by_kind.entry(kind.to_string()).or_default() += 1;
        if !kinds.is_empty() && !kinds.contains(kind) {
            continue;
        }
        total += 1;
        if rows.len() < limit {
            let mut row = symbol_json_of(&room, *o, &symbol_row(&room, &mut paths, &traits, *o));
            row["end_line"] = json!(v.end_line);
            row["path"] = json!(paths.of(*o));
            rows.push(row);
        }
    }
    let mut ev = room.mask(&MaskSpec { repos: repos_of(repo), origins: vec![Origin::Local], defined_only: true, ..Default::default() }).map_err(internal)?.evidence;
    ev.query = format!("symbols of {}", if repo.is_empty() { "every consumed repo" } else { repo });
    if total > rows.len() {
        ev.capped = Some(mimir_room::Capped { shown: rows.len() as u64, total: total as u64 });
    }
    super::p1_gap(&room, &mut ev);
    settle(&mut ev, rows.is_empty());
    Ok(with_identity(envelope(obj([("symbols", Value::Array(rows)), ("total", json!(total)), ("by_kind", json!(by_kind))]), &ev), handle, &room))
}

// ------------------------------------------------------------------ source

/// The bytes of `path` in commit `sha` of the clone at `dir`.
pub(super) fn blob_at(dir: &std::path::Path, sha: &str, path: &str) -> anyhow::Result<Vec<u8>> {
    let repo = gix::open(dir)?;
    let spec = format!("{sha}:{path}");
    let id = repo.rev_parse_single(spec.as_str())?;
    Ok(id.object()?.data.clone())
}

/// `Knowledge.Source`: where one item is and the text of its span — read
/// from the commit the room was consumed at (the consumer's own clone), so
/// the lines are the lines the spans count. The caller names a NODE
/// (`moniker`, or `name`: a path / path suffix), never a file.
pub fn source(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let room = open(reach, repo)?;
    let handle = reach.code_room()?;
    let (moniker, name) = (text(p, "moniker"), text(p, "name"));
    let asked = if moniker.is_empty() { name } else { moniker };
    let (nodes, mut ev) = match room.ordinal(asked) {
        Some(o) if !asked.is_empty() => (vec![o], room.mask(&MaskSpec::default()).map_err(internal)?.evidence),
        _ => resolve(&room, asked, if moniker.is_empty() { "name" } else { "moniker" })?,
    };
    ev.missing.clear();
    ev.notes.clear();
    ev.capped = None;
    ev.query = format!("source of `{asked}`");
    let mut paths = Paths::new(&room);
    let place = |o: u64, paths: &mut Paths<'_>| {
        let v = room.node(o);
        json!({ "path": paths.of(o), "moniker": v.moniker, "kind": v.kind, "crate": v.krate, "repo": v.repo, "file": v.file, "line": v.start_line, "end_line": v.end_line, "defined": v.defined })
    };
    let candidates: Vec<Value> = nodes.iter().take(20).map(|o| place(*o, &mut paths)).collect();
    // a definition with a span first; the room's own order otherwise
    let pick = nodes.iter().copied().filter(|o| room.span(*o).is_some()).min_by_key(|o| !room.node(*o).defined);
    let Some(o) = pick else {
        miss(
            &mut ev,
            "span",
            None,
            format!("`{asked}` is a node of the room with no span row ({} match(es)): a reference stub, an item of the dependency ring, or a binary-only node — there is no file to show", nodes.len()),
        );
        settle(&mut ev, true);
        return Ok(with_identity(envelope(json!({ "node": candidates.first(), "candidates": candidates, "lines": [] }), &ev), handle, &room));
    };
    if nodes.len() > 1 {
        note(&mut ev, &format!("`{asked}` names {} nodes of the room: the first definition with a span is shown, all are in `candidates`", nodes.len()));
    }
    let sp = room.span(o).expect("picked for its span");
    let (span_repo, file, start, end) = (sp.repo.to_string(), sp.file.to_string(), sp.start_line, sp.end_line.max(sp.start_line));
    let want = match p.get("max_lines").and_then(Value::as_u64) {
        Some(0) | None => SOURCE_LINES,
        Some(n) => (n as usize).min(SOURCE_LINES_MAX),
    };
    // a page further into a long item: from line `from` of its span
    let from = p.get("from").and_then(Value::as_u64).map(|f| f as u32).filter(|f| *f > start && *f <= end).unwrap_or(start);
    let sha = room.scope().offset_shas.get(&span_repo).cloned();
    let clone = handle.layout().clone_of(&span_repo);
    let mut lines: Vec<String> = Vec::new();
    let mut file_lines: Option<usize> = None;
    let mut truncated = false;
    match &sha {
        None => miss(&mut ev, "source text", Some(&span_repo), "the room is not at this repo's consumer offset (time travel): the commit of this state is not known here"),
        Some(sha) => match blob_at(&clone, sha, &file) {
            Err(e) => miss(&mut ev, "source text", Some(&span_repo), format!("`{file}` at {sha} could not be read from the consumer's clone {}: {e}", clone.display())),
            Ok(bytes) => {
                let all: Vec<&str> = std::str::from_utf8(&bytes).map(|t| t.lines().collect()).unwrap_or_default();
                file_lines = Some(all.len());
                if (start as usize) == 0 || start as usize > all.len() {
                    miss(
                        &mut ev,
                        "source text",
                        Some(&span_repo),
                        format!("`{file}` at {sha} has {} line(s); the span {start}–{end} lies outside it", all.len()),
                    );
                } else {
                    let last = (end as usize).min(all.len());
                    let first = (from as usize).min(last.max(1));
                    let stop = last.min(first - 1 + want);
                    truncated = stop < last;
                    lines = all[first - 1..stop].iter().map(|l| l.to_string()).collect();
                    if truncated {
                        ev.capped = Some(mimir_room::Capped { shown: lines.len() as u64, total: (last + 1 - start as usize) as u64 });
                    }
                }
            }
        },
    }
    settle(&mut ev, false);
    Ok(with_identity(
        envelope(
            json!({
                "node": place(o, &mut paths),
                "candidates": candidates,
                "repo": span_repo,
                "file": file,
                "start_line": start,
                "end_line": end,
                "from": from,
                "sha": sha,
                "lines": lines,
                "file_lines": file_lines,
                "truncated": truncated,
                "read_from": format!("the consumer's clone {}", clone.display()),
            }),
            &ev,
        ),
        handle,
        &room,
    ))
}

// ------------------------------------------------------------------ test reach

/// Is the node inside `#[cfg(test)]` code — itself or a container gated by a
/// `cfg` that requires `test`?
fn in_test_code(room: &Room, o: u64) -> bool {
    let mut cur = Some(o);
    for _ in 0..64 {
        let Some(c) = cur else { break };
        let n = room.node(c);
        if n.cfg.is_some_and(cfg_requires_test) {
            return true;
        }
        cur = n.parent;
    }
    false
}

/// `Knowledge.TestReach`: every fn and method a consumed repo defines, with
/// whether a test reaches it (`reach(tests, CALLS)` ∪ the TESTS targets) and
/// how many call sites arrive at it; and every test with what it reaches.
/// The coverage question a gate asks of the graph, answered by the graph.
pub fn test_reach(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let room = open(reach, repo)?;
    let handle = reach.code_room()?;
    let own = MaskSpec { repos: repos_of(repo), origins: vec![Origin::Local], defined_only: true, ..Default::default() };
    let callables = room.mask(&MaskSpec { node_kinds: vec![nk::FN.into(), nk::METHOD.into()], ..own.clone() }).map_err(internal)?;
    let tests = room.mask(&MaskSpec { repos: repos_of(repo), is_test: Some(true), ..Default::default() }).map_err(internal)?.value;
    let mut ev = callables.evidence;
    ev.missing.retain(|m| !m.input.starts_with("node kind"));
    // what the tests reach, together
    let mut covered: BTreeSet<u64> = BTreeSet::new();
    let mut named: BTreeMap<u64, u32> = BTreeMap::new();
    if tests.is_empty() {
        miss(
            &mut ev,
            "tests",
            None,
            "the room holds no `#[test]` / bench fn of this scope (no harness target was compiled at the consumed commit): `test_reachable` is false everywhere, and that is not a measurement",
        );
    } else {
        let walk = room.reach(&tests, &[EdgeKind::Calls], None, None).map_err(internal)?;
        absorb(&mut ev, &walk.evidence);
        covered.extend(walk.value.reached);
        // TESTS: what a test names directly (absent = no test names an item; a fact)
        let direct = room.edges(&EdgeSel { from: Some(&tests), ..EdgeSel::kinds(&[EdgeKind::Tests]) }).map_err(internal)?;
        for e in &direct.value.edges {
            covered.insert(e.to);
            *named.entry(e.from).or_default() += 1;
        }
    }
    // call sites arriving at each callable, from the scope's own definitions
    let local = room.mask(&own).map_err(internal)?.value;
    let arriving = room.edges(&EdgeSel { from: Some(&local), to: Some(&callables.value), ..EdgeSel::kinds(&[EdgeKind::Calls]) }).map_err(internal)?;
    absorb(&mut ev, &arriving.evidence);
    let mut fan_in: BTreeMap<u64, u32> = BTreeMap::new();
    for e in &arriving.value.edges {
        *fan_in.entry(e.to).or_default() += e.count;
    }
    let leaving = room.edges(&EdgeSel { from: Some(&tests), ..EdgeSel::kinds(&[EdgeKind::Calls]) }).map_err(internal)?;
    let mut calls_out: BTreeMap<u64, u32> = BTreeMap::new();
    for e in &leaving.value.edges {
        *calls_out.entry(e.from).or_default() += 1;
    }
    let mut paths = Paths::new(&room);
    let mut fns: Vec<Value> = Vec::with_capacity(callables.value.len());
    let (mut surface, mut reached) = (0u64, 0u64);
    for o in callables.value.ordinals() {
        let v = room.node(*o);
        let test_code = v.is_test || in_test_code(&room, *o);
        let hit = covered.contains(o);
        if !test_code {
            surface += 1;
            reached += hit as u64;
        }
        fns.push(json!({
            "repo": v.repo,
            "crate_name": v.krate,
            // the nearest enclosing module (a method's `module_path` is its type)
            "module": room.module_of(*o).map(|x| paths.of(x)).unwrap_or_default(),
            "module_path": v.parent.map(|x| paths.of(x)).unwrap_or_default(),
            "item_name": v.name,
            "fqn": paths.of(*o),
            "kind": v.kind,
            "visibility": v.visibility,
            "file": v.file,
            "line": v.start_line,
            "test_code": test_code,
            "test_reachable": hit,
            "fan_in": fan_in.get(o).copied().unwrap_or(0),
        }));
    }
    // each test's own reach: the items and files it stands on
    let mut files: Vec<Value> = Vec::new();
    let mut file_ix: BTreeMap<(String, String), usize> = BTreeMap::new();
    let mut test_rows: Vec<Value> = Vec::with_capacity(tests.len());
    for (i, t) in tests.ordinals().iter().enumerate() {
        let v = room.node(*t);
        let mut row = json!({
            "repo": v.repo,
            "crate_name": v.krate,
            "module": room.module_of(*t).map(|x| paths.of(x)).unwrap_or_default(),
            "module_path": v.parent.map(|x| paths.of(x)).unwrap_or_default(),
            "test_name": v.name,
            "fqn": paths.of(*t),
            "file": v.file,
            "line": v.start_line,
            "calls_out": calls_out.get(t).copied().unwrap_or(0),
            "names": named.get(t).copied().unwrap_or(0),
        });
        if let Some(h) = room.attr(*t, "ignored").and_then(|a| a.as_bool()) {
            row["is_heavy"] = json!(h);
        }
        if i < TEST_WALK_CAP {
            let walk = room.reach(&[*t][..], &[EdgeKind::Calls], None, None).map_err(internal)?.value;
            let mut in_files: BTreeSet<usize> = BTreeSet::new();
            let mut items = 0u64;
            for o in walk.reached.iter().filter(|o| *o != t) {
                let n = room.node(*o);
                if n.origin != Some(Origin::Local) || !n.defined {
                    continue;
                }
                items += 1;
                if let Some(s) = room.span(*o) {
                    let next = files.len();
                    let ix = *file_ix.entry((s.repo.to_string(), s.file.to_string())).or_insert_with(|| {
                        files.push(json!({ "repo": s.repo, "file": s.file }));
                        next
                    });
                    in_files.insert(ix);
                }
            }
            row["reached"] = json!(items);
            row["files"] = json!(in_files);
        }
        test_rows.push(row);
    }
    if tests.len() > TEST_WALK_CAP {
        miss(&mut ev, "per-test reach", None, format!("{} test(s): the own reach of the first {TEST_WALK_CAP} is walked, the others carry no `reached` / `files`", tests.len()));
    }
    ev.query = format!("what the tests of {} reach", if repo.is_empty() { "every consumed repo" } else { repo });
    note(
        &mut ev,
        "test_reachable = in `reach(tests, CALLS)` or a TESTS target; test_code = a test, or an item inside `#[cfg(test)]` code (not part of the surface); \
         fan_in = call sites arriving from the scope's own definitions; a test's `files` are indexes into `files`",
    );
    note(&mut ev, "tests of targets the consumer's `cargo check` did not compile (a harness behind a feature that is off) are not in the graph");
    note(&mut ev, LOWER_BOUND);
    settle(&mut ev, fns.is_empty());
    Ok(with_identity(
        envelope(
            obj([
                ("fns", Value::Array(fns)),
                ("tests", Value::Array(test_rows)),
                ("files", Value::Array(files)),
                ("surface_fns", json!(surface)),
                ("test_reachable", json!(reached)),
                ("tests_total", json!(tests.len())),
            ]),
            &ev,
        ),
        handle,
        &room,
    ))
}

// ------------------------------------------------------------------ diff

/// What a snapshot diff adds per crate: how many of the added / removed /
/// changed nodes are symbols of which `name@version`, and which crates are in
/// only one of the two states.
pub fn diff_by_crate(older: &Room, newer: &Room, added: &[String], removed: &[String], changed: &[String]) -> Value {
    #[derive(Default)]
    struct Delta {
        symbols: [u64; 3],
        nodes: [u64; 3],
    }
    let mut by: BTreeMap<String, Delta> = BTreeMap::new();
    for (slot, list, room) in [(0usize, added, newer), (1, removed, older), (2, changed, newer)] {
        for m in list {
            let Some(o) = room.ordinal(m) else { continue };
            let v = room.node(o);
            let Some(k) = v.krate else { continue };
            let d = by.entry(format!("{k}@{}", v.version.unwrap_or(""))).or_default();
            d.nodes[slot] += 1;
            d.symbols[slot] += SYMBOL_KINDS.contains(&v.kind.unwrap_or("")) as u64;
        }
    }
    let keys = |room: &Room| -> BTreeSet<String> {
        room.quotient(GroupBy::Crate, &[], None).map(|q| q.value.groups.into_iter().map(|g| g.key).collect()).unwrap_or_default()
    };
    let (a, b) = (keys(older), keys(newer));
    json!({
        "crates_added": b.difference(&a).collect::<Vec<_>>(),
        "crates_removed": a.difference(&b).collect::<Vec<_>>(),
        "crates": by.iter().map(|(k, d)| json!({
            "crate": k,
            "symbols_added": d.symbols[0], "symbols_removed": d.symbols[1], "symbols_changed": d.symbols[2],
            "nodes_added": d.nodes[0], "nodes_removed": d.nodes[1], "nodes_changed": d.nodes[2],
        })).collect::<Vec<_>>(),
    })
}

/// The two states `Coderoom.SnapshotDiff` compares when the request names a
/// repo and no states: its last two consumer ordinals — or, with one consumed
/// commit, the empty state before it.
pub fn last_two(handle: &CodeRoom, repo: &str) -> Result<(String, String, Option<String>), Refusal> {
    if repo.is_empty() {
        return Err(invalid(
            "snapshot-diff takes two states of the code room as `snap_a` / `snap_b` (`repo@seq`, consumer ordinals), or a `repo` (its last two ordinals) — got neither",
        ));
    }
    let head = open_in(handle, repo)?;
    let top = head.scope().repos.get(repo).copied().unwrap_or(0);
    let why = (top <= 1).then(|| format!("`{repo}` has ONE consumed commit (seq {top}): it is compared with the empty state before it — every node reads as added"));
    Ok((format!("{repo}@{}", (top - 1).max(0)), format!("{repo}@{top}"), why))
}

// ------------------------------------------------------------------ binary

/// Symbol rows `Viz.Binary` hands out when the request names no cap.
const BINARY_SYMBOLS_CAP: usize = 500;

/// One linked artifact as `Viz.Binary` lists it.
#[derive(Default)]
struct ArtifactSum<'a> {
    binary: Option<&'a str>,
    symbols: u64,
    bytes: u64,
    imports: u64,
}

/// Does `want` name `artifact` (its `name@triple:profile`, its file name, or the name before `@`)?
fn names_artifact(want: &str, artifact: &str, binary: Option<&str>) -> bool {
    let base = want.rsplit('/').next().unwrap_or(want);
    artifact == want || binary == Some(base) || artifact.split('@').next() == Some(base)
}

/// One artifact a Build Thing run filed with this server (builder 2), as
/// `Viz.Binary` lists it: the product node under `@build-thing` and — when
/// the server analysed it — its `binary_facts` header.
struct Built {
    hit: mimir_ingest::ArtifactHit,
    sha256: String,
    header: Option<crate::warehouse::iceberg::BinaryFactRow>,
}

/// The content sha256 an artifact node id carries (`… artifact=<sha256>`).
fn sha_of_artifact_id(id: &str) -> String {
    id.split("artifact=").nth(1).map(|t| t.chars().take_while(|c| c.is_ascii_hexdigit()).collect()).unwrap_or_default()
}

/// Every artifact a Build Thing run filed with this server
/// (`mimir_ingest::product::artifacts` over `@build-thing`, the products no
/// consumer offset covers), with its analysed header when the warehouse has
/// one. `Err` = the products could not be read (the answer names it).
fn built_artifacts(reach: &Reach<'_>, handle: &CodeRoom) -> Result<Vec<Built>, String> {
    let log = handle.log().map_err(|r| format!("[{}] {}", r.state, r.note))?;
    let hits = log
        .block_on(async {
            let pinned = log.pin().await?;
            mimir_ingest::product::artifacts(&pinned, &mimir_ingest::ArtifactQuery::default()).await
        })
        .map_err(|e| format!("{e:#}"))?;
    Ok(hits
        .into_iter()
        .map(|hit| {
            let sha256 = sha_of_artifact_id(&hit.id);
            let header = reach.warehouse.and_then(|wh| wh.query_binary_facts(&sha256).ok().flatten());
            Built { hit, sha256, header }
        })
        .collect())
}

/// Does `want` name the built artifact `b` (its file, its owner, or a sha256 prefix of ≥ 7)?
fn names_built(want: &str, b: &Built) -> bool {
    let base = want.rsplit('/').next().unwrap_or(want);
    b.hit.file == base || b.hit.owner == want || (want.len() >= 7 && b.sha256.starts_with(want))
}

/// `Viz.Binary`: the BINARY half — what mimir-binary joined into the room
/// from the linked artifacts (`code_symbols`) AND every artifact a Build
/// Thing run filed with this server (builder 2: the products under
/// `@build-thing`, analysed into the warehouse's `binary_facts` /
/// `section_sizes` / `symbol_sizes` by content sha256). `artifacts` lists
/// both, each with its `source` (`room` · `build`). For ONE of them
/// (`artifact`, default: the room artifact linking the most bytes, else the
/// largest build): its bytes by crate, its largest symbols (`limit`,
/// default 500) and — room — its size per binary release (the ledger,
/// `bin_ingest_runs`) or — build — its hardening (`checksec`, measured by
/// the server's analysis). `repo` narrows the room half to one repo.
///
/// Neither half has anything: the binary stream's state (`no_artifact` /
/// `not_consumed`), and the note says no build filed one either — never an
/// empty binary.
pub fn binary(reach: &Reach<'_>, p: &Value) -> Result<Value, Refusal> {
    let repo = text(p, "repo");
    let handle = reach.code_room()?;
    let built = built_artifacts(reach, handle);
    let built_list: &[Built] = built.as_ref().map(Vec::as_slice).unwrap_or(&[]);
    // the room half: a workspace nothing was consumed of still has its builds
    let room = match open(reach, repo) {
        Ok(r) => Some(r),
        Err(r) if r.state == State::NotConsumed && !built_list.is_empty() => None,
        Err(r) => return Err(r),
    };
    let symbols = match &room {
        Some(r) => Some(r.symbols(None, None).map_err(internal)?),
        None => None,
    };
    let linked: &[mimir_room::SymbolView<'_>] = symbols.as_ref().map(|a| a.value.as_slice()).unwrap_or(&[]);
    if linked.is_empty() && built_list.is_empty() {
        let builds = match &built {
            Ok(_) => "no Build Thing run has filed an artifact with this server either (`Coderoom.Artifacts` is empty)".to_string(),
            Err(e) => format!("the artifacts Build Thing runs filed could not be read either: {e}"),
        };
        let room = room.as_ref().expect("no room only when there are builds");
        let mut r = super::no_linked_symbol(reach, room, "there is no binary to show, and that is not an empty binary");
        r.note = format!("{}; {builds}", r.note);
        return Err(r);
    }
    let mut ev = symbols.as_ref().map(|a| a.evidence.clone()).unwrap_or_default();
    if room.is_none() {
        ev.query = "binary".into();
        super::note(&mut ev, "nothing of this workspace was consumed: only the artifacts Build Thing runs filed are listed");
    }
    if let Err(e) = &built {
        super::miss(&mut ev, "@build-thing products", None, format!("the artifacts Build Thing runs filed were not read: {e}"));
    }
    // per room artifact
    let mut arts: BTreeMap<&str, ArtifactSum<'_>> = BTreeMap::new();
    for s in linked {
        let a = arts.entry(s.artifact).or_default();
        a.binary = a.binary.or(s.binary);
        match s.size {
            Some(n) => {
                a.symbols += 1;
                a.bytes += n;
            }
            None => a.imports += 1,
        }
    }
    // which one is shown
    enum Pick<'b> {
        Room(&'b str),
        Build(&'b Built),
    }
    let want = text(p, "artifact");
    let pick = if want.is_empty() {
        match arts.iter().max_by(|a, b| a.1.bytes.cmp(&b.1.bytes).then(b.0.cmp(a.0))) {
            Some((k, _)) => Pick::Room(k),
            None => Pick::Build(built_list.iter().max_by_key(|b| b.header.as_ref().map_or(0, |h| h.total_bytes)).expect("a build when no room artifact")),
        }
    } else if let Some((k, _)) = arts.iter().find(|(k, a)| names_artifact(want, k, a.binary)) {
        Pick::Room(k)
    } else if let Some(b) = built_list.iter().find(|b| names_built(want, b)) {
        Pick::Build(b)
    } else {
        let mut known: Vec<String> = arts.keys().map(|k| k.to_string()).collect();
        known.extend(built_list.iter().map(|b| b.hit.owner.clone()));
        let scope = room.as_ref().map(|r| r.scope().to_string()).unwrap_or_default();
        return Err(super::invalid(format!("no linked or built artifact `{want}` in [{scope}] (known: {known:?})")));
    };
    let limit = limit_of(p, BINARY_SYMBOLS_CAP);
    let mut crates_of: BTreeMap<String, (u64, u64)> = BTreeMap::new();
    let mut symbols_out: Vec<Value> = Vec::new();
    let mut total = 0usize;
    let mut history: Vec<Value> = Vec::new();
    let mut latest: BTreeMap<String, Value> = BTreeMap::new();
    let (chosen, source, checksec) = match pick {
        Pick::Room(chosen) => {
            let room = room.as_ref().expect("a room artifact has a room");
            let mut paths = Paths::new(room);
            let mut sized: Vec<&mimir_room::SymbolView<'_>> = Vec::new();
            for s in linked.iter().filter(|s| s.artifact == chosen) {
                let Some(n) = s.size else { continue };
                let c = crates_of.entry(room.node(s.node).krate.unwrap_or("[unknown]").to_string()).or_default();
                c.0 += n;
                c.1 += 1;
                sized.push(s);
            }
            sized.sort_by(|a, b| b.size.cmp(&a.size).then(a.symbol.cmp(b.symbol)));
            total = sized.len();
            symbols_out = sized
                .iter()
                .take(limit)
                .map(|s| {
                    let v = room.node(s.node);
                    json!({
                        "symbol": s.demangled.unwrap_or(s.symbol), "mangled": s.symbol, "crate": v.krate.unwrap_or("[unknown]"),
                        "path": paths.of(s.node), "role": s.role, "section": s.section, "bytes": s.size,
                    })
                })
                .collect();
            // the size per binary release: the join ledger of each consumed repo
            match handle.log() {
                Ok(log) => {
                    for r in room.scope().repos.keys() {
                        match log.block_on(log.bin_runs(r)) {
                            Ok(rows) => {
                                for row in rows {
                                    let led: Value = row.ledger.as_deref().and_then(|l| serde_json::from_str(l).ok()).unwrap_or(Value::Null);
                                    let entry = json!({
                                        "repo": row.repo, "artifact": row.artifact, "rev": row.rev, "seq": row.seq, "sha": row.sha, "status": row.status,
                                        "file_size": led.get("file_size"), "text_size": led.get("text_size"), "has_dwarf": led.get("has_dwarf"),
                                    });
                                    latest.insert(row.artifact.clone(), entry.clone());
                                    if row.artifact == chosen {
                                        history.push(entry);
                                    }
                                }
                            }
                            Err(e) => super::miss(&mut ev, "bin_ingest_runs", Some(r.as_str()), format!("the binary stream's ledger was not read: {e:#}")),
                        }
                    }
                }
                Err(r) => super::miss(&mut ev, "bin_ingest_runs", None, format!("the binary stream's ledger was not read: [{}] {}", r.state, r.note)),
            }
            super::note(&mut ev, "hardening (RELRO · PIE · NX · stack canary · fortify) is not in the binary layer: mimir-binary joins symbols, it does not grade the ELF");
            (chosen.to_string(), "room", Value::Null)
        }
        Pick::Build(b) => {
            let analysis = match reach.warehouse {
                Some(wh) => crate::binscan::load_analysis(wh, &b.sha256).map_err(|e| format!("{e:#}")),
                None => Err("this door reaches no warehouse".to_string()),
            };
            let checksec = match analysis {
                Ok(Some((h, _sections, syms))) => {
                    let mut sized: Vec<&crate::warehouse::iceberg::SymbolSizeRow> = syms.iter().filter(|s| s.size_bytes > 0).collect();
                    for s in &sized {
                        let c = crates_of.entry(if s.crate_name.is_empty() { "[unknown]".to_string() } else { s.crate_name.clone() }).or_default();
                        c.0 += s.size_bytes as u64;
                        c.1 += 1;
                    }
                    sized.sort_by(|a, b| b.size_bytes.cmp(&a.size_bytes).then(a.symbol_mangled.cmp(&b.symbol_mangled)));
                    total = sized.len();
                    symbols_out = sized
                        .iter()
                        .take(limit)
                        .map(|s| {
                            json!({
                                "symbol": if s.symbol_demangled.is_empty() { &s.symbol_mangled } else { &s.symbol_demangled }, "mangled": s.symbol_mangled,
                                "crate": if s.crate_name.is_empty() { "[unknown]" } else { s.crate_name.as_str() }, "role": s.kind, "section": s.section, "bytes": s.size_bytes,
                            })
                        })
                        .collect();
                    super::note(&mut ev, &format!("a Build Thing artifact ({}, {}): sizes and hardening from the server's analysis of its bytes (binary_facts / symbol_sizes, sha256 {})", b.hit.variant, b.hit.target, &b.sha256[..b.sha256.len().min(16)]));
                    json!({ "relro": h.relro, "pie": h.pie, "nx": h.nx, "stack_canary": h.stack_canary, "fortify": h.fortify, "stripped": h.stripped, "total_bytes": h.total_bytes })
                }
                Ok(None) => {
                    super::miss(&mut ev, "binary_facts", None, format!("the build artifact {} (sha256 {}) was filed but not analysed on this server (its file was not readable here)", b.hit.file, &b.sha256[..b.sha256.len().min(16)]));
                    Value::Null
                }
                Err(e) => {
                    super::miss(&mut ev, "binary_facts", None, format!("the build artifact's analysis was not read: {e}"));
                    Value::Null
                }
            };
            (b.hit.owner.clone(), "build", checksec)
        }
    };
    if total > symbols_out.len() {
        ev.capped = Some(mimir_room::Capped { shown: symbols_out.len() as u64, total: total as u64 });
    }
    let mut crates: Vec<(String, (u64, u64))> = crates_of.into_iter().collect();
    crates.sort_by(|a, b| b.1.0.cmp(&a.1.0).then(a.0.cmp(&b.0)));
    let crates: Vec<Value> = crates.into_iter().map(|(k, (bytes, n))| json!({ "crate": k, "bytes": bytes, "symbols": n })).collect();
    let mut artifacts: Vec<Value> = arts
        .iter()
        .map(|(k, a)| {
            let led = latest.get(*k);
            json!({
                "artifact": k, "source": "room", "binary": a.binary, "symbols": a.symbols, "bytes": a.bytes, "imports": a.imports,
                "file_size": led.and_then(|l| l.get("file_size")).cloned().unwrap_or(Value::Null),
                "text_size": led.and_then(|l| l.get("text_size")).cloned().unwrap_or(Value::Null),
            })
        })
        .collect();
    artifacts.extend(built_list.iter().map(|b| {
        json!({
            "artifact": b.hit.owner, "source": "build", "binary": b.hit.file, "variant": b.hit.variant, "target": b.hit.target, "sha256": b.sha256,
            "bytes": b.header.as_ref().map(|h| h.total_bytes), "commits": b.hit.commits,
        })
    }));
    ev.query = format!("binary of {}", if repo.is_empty() { "every consumed repo" } else { repo });
    settle(&mut ev, false);
    let body = obj([
        ("artifacts", Value::Array(artifacts)),
        ("artifact", json!(chosen)),
        ("source", json!(source)),
        ("checksec", checksec),
        ("crates", Value::Array(crates)),
        ("symbols", Value::Array(symbols_out)),
        ("total_symbols", json!(total)),
        ("history", Value::Array(history)),
    ]);
    let body = envelope(body, &ev);
    Ok(match &room {
        Some(r) => with_identity(body, handle, r),
        None => body,
    })
}