Mímir v2 — the Rust code graph
Mímir v2 is nornir's code graph. One producer (a rustc driver) writes Arrow IPC files per compiled crate. One consumer folds them into an Iceberg/Parquet lake. One in-memory room (GraphBLAS) answers questions through named reader surfaces and lenses. Every node id is a SCIP moniker string.
This document describes the code on main as it is today. File references are repo-relative paths in nornir unless another repo is named. A short list of planned items sits at the end, marked as planned.
Chapters:
| file | content |
README.md (this file) |
flow, producer, ids, lake, room, readers, lenses, what is not there, the system boundary and the possible system calls |
tables.md |
every table and every column |
1. Glossary
| word | meaning |
| unit | one crate compiled once by cargo (a lib, a bin, a test harness, a dependency) |
| dump | the Arrow IPC files mimir-driver writes for one unit |
| moniker | a node id: a SCIP symbol string, rust-analyzer cargo <package> <version> <descriptors> |
| member | a repo the nornir workspace registry lists |
| consumer | the nornir server loop that clones a member, checks out a commit, runs the dump and writes the lake |
| lake | the skade warehouse (Iceberg tables, Parquet files) under <builds>/mimir_v2/lake |
| event table | an append-only table of + / - rows; the graph at a commit is the fold of its events |
| open set | the rows of a repo with a + and no later - |
| universe | the dependency ring: dependency and toolchain crates, dumped once per crate@version and toolchain, kept apart from the members' rows |
| room | mimir-room's in-memory Snapshot: node table, spans, one GraphBLAS matrix per edge kind |
| scope | which repos at which sequence number, universe on or off |
| surface | a named reader question (Viz.CrateGraph, Knowledge.Source, …) answered over gRPC CodeRoom.Answer |
| lens | a named analysis over the room (generic_cost, zombie_features, change_risk, …) |
| skade | our Iceberg/Parquet warehouse crate |
| gix | the pure-Rust git library used to read file text at a commit |
2. Flow
repo clone at commit C
│
▼
cargo-mimir-dump ──► cargo check --workspace --all-targets
RUSTC_WRAPPER=mimir-driver RUSTUP_TOOLCHAIN=nightly-2026-10-05
target dir: target/mimir env: MIMIR_OUT MIMIR_REPO MIMIR_SHA …
│
│ per unit: <crate>@<version>-<hash>.nodes.arrow
│ <crate>@<version>-<hash>.edges.arrow
│ <crate>@<version>-<hash>.spans.arrow
│ <crate>@<version>-<hash>.symbols.arrow
│ <crate>@<version>-<hash>.stats.json
▼
┌────────────────────────────────────────────┐ ┌──────────────────────────────────┐
│ nornir code room (server) │ │ dwarves `cargo lens graph-package` │
│ consumer: read_out_dir → delta vs open set │ │ reads *.edges.arrow, kind CALLS │
│ ONE skade atomic release per (repo, sha) │ │ joins with cargo metadata + lock │
│ lake: <builds>/mimir_v2/lake (Parquet) │ │ writes target/dwarves/ │
│ mimir-room: fold → Snapshot (GraphBLAS) │ │ graph-package.znippy │
│ reader::door surfaces + mimir_lens::answer │ │ (see dwarves docs/v2/README.md) │
│ gRPC CodeRoom.Answer :7878 │ └──────────────────────────────────┘
│ proxied by the dwarves forge on :7900 │
└────────────────────────────────────────────┘
│
▼
dwarves-gui (Coderoom tab, graph source pane) → facett CoderoomPane
3. The producer
3.1 cargo-mimir-dump
crates/mimir-driver/src/bin/cargo-mimir-dump.rs. It is a cargo subcommand (cargo mimir-dump) that does two things:
- One
cargo metadata, written to<out>/crate-versions.json(MIMIR_CRATE_VERSIONS). cargo check --workspace --all-targets(orcargo buildwith--build) with the driver as the rustc wrapper.
| setting | value | where |
| toolchain | nightly-2026-10-05 (RUSTUP_TOOLCHAIN) |
crates/mimir-driver/src/lib.rs MIMIR_NIGHTLY, crates/mimir-driver/rust-toolchain.toml |
| wrapper | RUSTC_WRAPPER=mimir-driver (every crate, dependencies included); --workspace-wrapper uses RUSTC_WORKSPACE_WRAPPER instead (members only) |
cargo-mimir-dump.rs |
| target dir | <workspace>/target/mimir by default (--target-dir); nightly fingerprints are kept apart from stable's |
cargo-mimir-dump.rs |
| output dir | --out DIR, passed as MIMIR_OUT |
cargo-mimir-dump.rs |
| index dir | MIMIR_INDEX_DIR = <target dir>/mimir-index |
cargo-mimir-dump.rs |
| repo name | --repo NAME, passed as MIMIR_REPO (the directory name by default) |
cargo-mimir-dump.rs |
| commit | git rev-parse HEAD, passed as MIMIR_SHA |
cargo-mimir-dump.rs |
| other flags | --manifest-path, --workspace-only, --build, --std, --driver PATH, -- <cargo check args> |
cargo-mimir-dump.rs USAGE |
| exit code | 0 ok; cargo's code when cargo check fails; 3 when cargo metadata fails |
cargo-mimir-dump.rs |
The nornir consumer runs it with --keep-going, so every crate that compiles is dumped even when another does not (crates/mimir-ingest/src/driver.rs).
3.2 mimir-driver
crates/mimir-driver/src/main.rs. A clippy-shaped rustc driver: it drops cargo's rustc from argv, compiles in process with its linked nightly, and registers a rustc_driver::Callbacks whose after_analysis hook walks the TyCtxt and returns Compilation::Continue, so rustc still emits the metadata cargo expects. Proc macros, build scripts and --print calls are plain rustc. The walk is crates/mimir-driver/src/walk.rs (and walk/).
3.3 Helpers
| binary | role | where |
mimir-capture <stdout-file> -- <program> <args…> |
runs a tool, copies its stdout byte for byte to a file while streaming it; used on the container road, where the engine's log API frames stdout and would cut cargo metadata's one-line JSON |
crates/mimir-driver/src/bin/mimir-capture.rs |
mimir-super <job.json> |
the super build: one cargo-mimir-dump per repo of a workspace, run together over one target dir with cargo's -Zfine-grain-locking and one shared jobserver; writes <out>/.super/{cargo.json,cargo.err,exit,ms} per repo |
crates/mimir-driver/src/bin/mimir-super.rs |
3.4 The per-unit files
For every compiled unit the driver writes, under MIMIR_OUT:
<crate>@<version>-<hash>.nodes.arrow table code_nodes
<crate>@<version>-<hash>.edges.arrow table code_edges
<crate>@<version>-<hash>.spans.arrow table code_spans
<crate>@<version>-<hash>.symbols.arrow table code_symbols
<crate>@<version>-<hash>.stats.json counts and timings
<hash> is the short hash of the rustc invocation. A toolchain crate (core, std, …) has a URL as its version; its files say @lang (walk.rs, the stem computation).
Format: Arrow IPC file format (arrow_ipc::writer::FileWriter), one RecordBatch per file, written to a temporary name and renamed (walk.rs write_ipc). Every batch carries two schema metadata keys: mimir.schema = 5 and mimir.table = the table name (crates/mimir-schema/src/lib.rs SCHEMA_VERSION, META_SCHEMA, META_TABLE).
The columns of the four tables, the node kinds and the edge kinds are in tables.md. In short:
| table | one row per | key columns |
code_nodes |
item (crate, mod, fn, struct, field, param, feature, …) | id, kind, level, name, parent, repo, crate, version, file, start_line, end_line, cfg, origin, provenance, visibility and doc columns |
code_edges |
semantic edge (from, to, kind) |
from, to, kind, count, provenance, negated/partial (GATED_BY), access (TOUCHES_TABLE) |
code_spans |
position of a node or of one edge site | target (node/edge), key, file, start_line, end_line |
code_symbols |
linked symbol | id, symbol, demangled, role, crate, version, binary, section, addr, size |
MIR facts are not a separate file. They are extra rows at level part (mir_body per fn, mir_block per basic block) inside code_nodes and code_edges (walk.rs module doc).
Positions live apart from identity: an edge row has no line numbers; its sites are code_spans rows with target = "edge" and key = from ␞ to ␞ KIND (mimir_schema::edge_key, separator U+001E). Moving code changes spans, never an edge.
4. Ids: SCIP monikers, no SCIP tooling
Every node id is a SCIP symbol string in the shape rust-analyzer scip emits:
rust-analyzer cargo <package> <version> <descriptors>
The one formatter is crates/mimir-schema/src/moniker.rs. Nothing else assembles that string, so two producers that name the same definition write the same bytes.
| descriptor suffix | form | used for |
| Namespace | name/ |
modules, the crate root crate/ |
| Type | name# |
struct, enum, union, trait, type alias, variant |
| Term | name. |
const, static, field |
| Method | name(). |
fn, method |
| TypeParameter | [name] |
generic params, impl self/trait slots |
| Parameter | (name) |
fn params |
| Meta | name: |
derive/attribute macros, non-lib target prefix ( bin=x: ), mono instances, cargo features ( feature=x: ) |
| Macro | name! |
bang macros |
A non-lib target (bin, test, bench, example) gets one leading Meta descriptor naming the target, because rust-analyzer gives those the lib's ids. Impl scopes are rust-analyzer's: impl#[Self]new()., impl#[Dog][Greet]greet()..
What this is not: there is no index.scip, no scip-* indexer and no SCIP protobuf anywhere in the path. Only the id grammar is SCIP's. Readers that need the package of a callee parse it out of the moniker (the dwarves join does this in crates/dwarves/src/lens_graph.rs moniker_package).
5. Ingest into the lake
The nornir server's code room (src/code_room/) is the only writer of the lake.
5.1 The consumer loop
src/code_room/consumer_loop.rs, crates/mimir-ingest/src/consumer.rs. For a member:
- Its own clone under
<builds>/mimir_v2/clones/<member>(git::sync_clone); the server's registry clone is not touched (src/code_room/mod.rs). - Checkout of the next commit after the member's offset (
checkout::checkout_changed). cargo-mimir-dumpon that tree (section 3.1), on one of three roads:
| road | setting | where |
| installed | NORNIR_MIMIR_DRIVER = path of cargo-mimir-dump (its sibling mimir-driver is the wrapper); without it: <nornir home>/mimir-driver/, beside the binary, then PATH |
src/code_room/driver.rs |
| wrapped | NORNIR_MIMIR_DRIVER_HOST = a command line every tool is started through (for example a podman run … <toolchain image>); NORNIR_MIMIR_TOOLCHAIN names the nightly when it is not the pinned one |
src/code_room/driver.rs |
| container | NORNIR_MIMIR_CONTAINER_IMAGE (+ NORNIR_MIMIR_CONTAINER_DRIVER, a host dir with cargo-mimir-dump, mimir-driver, mimir-capture built for the image; NORNIR_MIMIR_CONTAINER_BINDS): every tool runs in that image through draupnir, under mimir-capture; tried first, the host road taken when it does not work |
src/code_room/container.rs, containers/mimir-driver/Containerfile |
read_out_dirreads the unit files back (crates/mimir-ingest/src/driver.rs).- Delta against the open set: rows the new dump has and the open set lacks become
+events, rows the open set has and the dump lacks become-events. - One skade atomic release: the event tables, the consumer offset and the ledger rows (and the universe manifest when it moved) advance together or not at all (
crates/mimir-ingest/src/log.rscommit, under one commit lock).
5.2 Where and how it is stored
| item | value | where |
| warehouse | skade, namespace mimir_v2 |
crates/mimir-ingest/src/schema.rs NAMESPACE |
| directory | <builds>/mimir_v2/lake |
src/code_room/mod.rs |
| clones | <builds>/mimir_v2/clones/<member> |
src/code_room/mod.rs |
| data files | Parquet, zstd level 3, 256 k-row row groups | log.rs write_props |
| catalog | skade's (redb) | skade |
| event prefix | repo, seq, sha, op, krate, payload_hash, key_dup, rev ahead of the payload columns of section 3.4 |
schema.rs PREFIX |
| universe rows | repo = "@universe", in their own universe_*_events tables once the lake is split |
schema.rs UNIVERSE_REPO, PROP_RING |
The tables (details in tables.md):
| stream | tables |
| source (driver dumps) | code_node_events, code_edge_events, code_span_events |
| universe ring | universe_node_events, universe_edge_events, universe_span_events, universe_manifest |
binary (mimir-binary) |
code_symbol_events, bin_node_events, bin_edge_events, bin_ingest_runs, bin_offsets |
| bookkeeping | consumer_offsets, ingest_runs, consumer_feed_runs, backfill_runs |
Provenance (source_only / binary_only / both) is derived at read time by joining the source and binary streams on the moniker; it is not stored as a fact of the room.
6. mimir-room: the in-memory snapshot
crates/mimir-room/src/lib.rs, snapshot.rs, scope.rs.
A Scope is a map repo → seq plus universe: bool. Folding the log at a scope gives an immutable Snapshot:
| part | content | where |
Monikers |
every node id, sorted; the position is the node's dense ordinal | snapshot.rs |
NodeTable |
interned strings and every payload column of code_nodes by name |
snapshot.rs |
| spans and sites | node spans and edge sites (file, lines) of the scope's repos | snapshot.rs, attrs.rs |
Matrices |
one boolean CSR GrB_Matrix per EdgeKind; unions over several kinds and transposes built on first use and kept |
snapshot.rs |
| symbols | the linked symbols (size, section, role, artifact) | snapshot.rs |
| provenance | derived per node (mimir_schema::derive_provenance) |
lib.rs |
Room = Arc<Snapshot>. A built snapshot is cached per process, keyed by the log identity (the event tables' UUIDs) and the resolved scope; a new commit to any event table moves the log's stamp and drops that log's entries.
The graph engine is crates/mimir-graph: a small safe layer over SuiteSparse:GraphBLAS through crates/graphblas-sys. It imports boolean adjacency from CSR or from Arrow (from_ord, to_ord) batches and provides the semiring operations the lenses use: reachability forward and reverse with many seeds, fan-in/fan-out, fewest hops (MIN_PLUS), worst value on a path (MAX_SECOND), scope masks, A·Aᵀ similarity, connected components, diff. Every handle is RAII (GrB_free on drop); the library is initialised once per process.
The typed query API (no query language):
| question | call |
| what is this node | Room::node, attr, display_path, span, sites |
which node is a::b::c |
Room::lookup |
| node sets | Room::mask, mask_of, Mask::union |
| walks | Room::reach, dependents, dependents_by, hops_from, min_hops_to, path |
| weights | Room::bottleneck, worst_on_path |
| edges out, collapsed | Room::edges, Room::quotient (by crate, module, repo, file) |
| binary | Room::symbols, symbols_of, instances_of |
| identity | Room::duplicate_keys, Room::diff |
Every answer carries Evidence: which tables fed the room, which edge kinds the query walked, and what is missing. With the universe off, walks stop at the reference stubs of dependency and std items and the evidence says so (query.rs). A SYSCALLS walk says MISSING until the universe is folded in: the boundary producer writes its edges into the universe (section 10).
7. Readers: surfaces, the code room door, and the panes
src/code_room/reader/wired.rs dispatches a surface name to a function over a Reach (the room plus the workspace it was read from). The surfaces on main:
Knowledge.SymbolLookup Knowledge.DefinedIn Knowledge.Callers Knowledge.Callees
Knowledge.CallPath Knowledge.FeatureGates Knowledge.Context Knowledge.Map
Knowledge.Symbols Knowledge.Source Knowledge.TestReach
Viz.Knowledge Viz.Architecture Viz.CrateGraph Viz.CallGraph Viz.FunctionTier
Viz.CodeMap Viz.Binary Viz.TestMatrix.inventory
Test.List Test.Affected Arch.History Mimir.SqlTemplate Mimir.SystemBoundary
Two of them are what the code room panes draw:
| surface | answer | where |
Viz.CrateGraph |
the room collapsed by crate: one node per name@version, one join per pair with its DEPENDS_ON, CALLS and USES_TYPE counts (room.quotient(GroupBy::Crate, …)) |
src/code_room/reader/wired/panes.rs crate_graph |
Knowledge.Source { moniker } |
where the item is (repo, file, span) and the text of the span, read with gix from the consumer's clone at the commit the room was consumed at (scope().offset_shas[repo]), so line numbers match the spans |
panes.rs source, blob_at |
Wire: gRPC CodeRoom.Answer on the nornir server (loopback :7878 by default, --addr / NORNIR_SERVER_ADDR; src/server_grpc.rs). The dwarves forge proxies the same service on its own port (:7900, dwarves crates/dwarves/src/warehouse_proxy.rs CodeRoomProxy), so one URL gives a client the forge and the room.
Who asks: dwarves-gui's Coderoom tab (dwarves-gui/src/coderoom.rs) mounts facett's shared CoderoomPane (facett-coderoom-view) behind a CoderoomDataSeam that asks Viz.CrateGraph and Coderoom.SnapshotDiff; the graph source pane (dwarves-gui/src/graph_source.rs) asks Knowledge.Source for the node a person clicked. Neither reads a table or a file; the seam is dwarves-gui/src/room.rs (ForgeRoom, CodeRoom.Answer through the forge).
8. Lenses
src/mimir_lens/mod.rs answer(lens, reach, params) -> Value is the one entry. The names it accepts (LENSES):
generic_cost zombie_features change_risk similar_code semantic_clones weak_tests
bench_gaps villa churn anomaly world_impact binary_drift data_reach trust
name_collision symbol_identity reachable_vuln undoc_api system_boundary
exact_clones near_clones structural_clones role_neighbours same_intent
semantic_twins reimplements_shared
An unknown name is refused with the known list. Each lens module sits beside mod.rs (bloat.rs answers generic_cost, zombie.rs answers zombie_features, risk.rs answers change_risk, …). The dwarves CLI's short names map onto them in dwarves crates/dwarves/src/room_read.rs: bloat → Mimir.GenericCost, zombie → Mimir.ZombieFeatures, risk → Mimir.ChangeRisk.
A lens answer carries the same Evidence as a room query; a lens whose room feed is not wired for a repo says not_wired instead of returning zeros.
9. What is NOT there
| item | state | where |
symbol_facts, call_edges, feature_gate_facts, scip_occurrences, test_inventory, warehouse_access_edges, architecture_wiring, knowledge_scans, semantic_clusters, lens_runs, feed_runs |
v1 tables with no writer; listed so no reader is written for them again | src/code_room/status.rs V1_TABLES |
universal SCIP import (index.scip from any scip-* indexer) and the syn tarball scan |
removed with v2; only the moniker grammar stayed | crates/mimir-schema/src/moniker.rs |
Coderoom.Compat, Coderoom.WhatBreaks |
answered not_wired: the world ring (crates.io versions of other crates) has no producer |
dwarves-gui/src/coderoom.rs module doc |
| a git remote URL per repo in the lake | not stored; the registry row has it | src/registry.rs |
| file text in the lake | not stored; read on demand with gix (section 7) |
panes.rs |
10. The system boundary and the possible system calls
The kernel tooling as a whole (Build Thing, Heimdall tooling, Mímir, and the files between them) is described in heimdall docs/v2/kernel-tooling.md.
10.1 The boundary in the universe
crates/mimir-ingest/src/boundary/ writes the system boundary into the dependency universe, once per toolchain and target, after a consume (src/code_room/consumer_loop.rs ensure_boundary → boundary::ensure):
| owner | rows | where |
@syscall@<arch>.r1:table |
one syscall node per call of the architecture's kernel table (ty = its class, doc = number and entry point) plus <indirect> |
boundary/mod.rs table_rows |
@syscall@<owner>.<key>.r1:map |
per dependency owner: SYSCALLS edges from its ffi nodes (through the glibc / musl map), from fns that hand the raw door a number, and from the raw door to <indirect>; key is the libc on x86_64 and <arch>-<libc> on every other architecture |
boundary/mod.rs map_edges, map_owner, Target::map_key |
@kernel@<release>+<hash>:btf |
the kernel's types and functions from BTF; CALLS from each syscall node to its entry function | boundary/mod.rs kernel_rows, boundary/btf.rs |
The syscall tables:
| arch | source | file |
x86_64 |
linux-6.12.104 arch/x86/entry/syscalls/syscall_64.tbl (common + 64), numbers past it from the UAPI <asm/unistd_64.h> of linux-libc-dev 7.0.0-38 |
boundary/x86_64.rs (generated by boundary/gen/gen_x86_64.py) |
aarch64 |
linux-6.12.104 scripts/syscall.tbl with the ABIs arm64 builds (common, 64, renameat, rlimit, memfd_secret), numbers past it from the UAPI <asm-generic/unistd.h> of linux-libc-dev 7.0.0-38 |
boundary/aarch64.rs (generated by boundary/gen/gen_aarch64.py) |
The libc map names x86_64's calls. aarch64 has no legacy calls (open, stat, fork, pipe …): boundary::calls_on(arch, name) turns each one into the call(s) the C library makes there instead (boundary::GENERIC_STAND_INS: open → openat, rename → renameat, renameat2, …), so no mapped call is dropped on aarch64. A legacy call with no stand-in (iopl, modify_ldt, the x86 thread-area calls) has no edge.
10.2 The possible system calls (the max)
crates/mimir-room/src/possible.rs, Room::possible_syscalls(entries, opts), and the CLI verb:
mimir-room <lake> possible [ENTRY…] [--bin NAME] [--target TRIPLE] [--binary NAME] [--out FILE] [--runtime off] [--repo NAME]…
ENTRY is a moniker or a readable path of a fn; --bin NAME takes the main of that bin target (moniker ending bin=NAME:main(). , - read as _: the crate name). The room is opened with the universe folded in. The verb refuses to write a file when an entry is unknown or the room holds no syscall node of the target's architecture.
With --bin the program is a linked executable (PossibleOpts::runtime, off with --runtime off): std's rt::lang_start and rt::lang_start_internal are entries too when the room holds them, and the calls the C runtime's start-up makes before main are possible, with the path <C runtime start-up, before main> (mimir_ingest::boundary::libc_map::startup: musl on x86_64 arch_prctl, set_tid_address; glibc adds set_robust_list and, uncertain, rseq, prlimit64, brk, mmap, mprotect, readlinkat, getrandom). A source graph never sees that code.
The walk is breadth-first over CALLS and SYSCALLS from the entries; a syscall node is an end (the walk does not go on into kernel functions). It runs twice: first over resolved edges only (what it reaches is direct), then from everything reached, widened at every unresolved site:
| site | how the driver writes it | how the walk widens it |
a trait method with no resolved impl (dyn Trait, a generic bound) |
CALLS to the trait's own method (walk.rs resolve keeps the trait method when the args are generic or dyn) |
every method of that name in every impl that IMPLEMENTS the trait, in the whole room |
a call through a value: a closure, a Box<dyn Fn…>, a generic F: Fn… |
CALLS to the Fn / FnMut / FnOnce method rustc records for the overloaded call (resolved to the impl when the type is concrete) |
the impls of that Fn* trait, and every fn a static or const initializer names (once) |
| a call through a fn pointer | CALLS to core::ops::function::Fn::call (a fn pointer implements Fn) |
as above |
a fn named as a value (x.map(a::tiny)) |
CALLS from the body that names it |
none needed: the edge is there |
our own extern "C" item (no SYSCALLS edge: the producer maps dependencies only) |
an ffi node |
the libc map, calls_on for the architecture |
the raw door (libc::syscall, a rustix raw stub) |
SYSCALLS to <indirect> |
none possible: listed, the number is chosen at run time |
Closure bodies are part of the fn that defines them (walk.rs BodyVisitor), so their calls are reached with that fn.
The output is the Graph JSON that dwarves-tune-graph's read_graph reads, with extra fields its reader ignores:
| field | type | content |
format |
string | mimir.possible-syscalls/1 |
binary, arch |
string | the program's name, the architecture |
modules |
array of {name, path, reached_functions} |
per crate (name@version) the fns reached; path = the repo or @universe |
entries |
array of string | the entry points (readable paths) |
syscalls |
map name → {nr, direct, path, site, sites, uncertain} |
path = the shortest chain entry → … → the fn that makes the call (a direct maker first); site = that fn with its crate; sites = how many reached fns make it; uncertain = every maker's hop is UNCERTAIN |
unnamed |
array of number | empty (a source graph names every call) |
unresolved_sites |
array of {module, function, offset, direct, callee, reason, targets} |
every widened site and every raw door reached; offset is 0; targets = how many targets the site was widened to |
missing_libs |
array | empty (the room holds every crate) |
unresolved_imports |
array of string | reached C functions the libc map has no answer for (they may make any call) |
dlopen |
bool | a reached C function is dlopen / dlmopen |
indirect_sites |
number | widened sites (dispatch + value calls) |
reached_functions |
number | fns, methods and ffi items reached |
The evidence (stderr of the verb) says MISSING when the universe is off, when no syscall table exists for the architecture, and when a reached C function is unmapped.
The binary walk and the source-graph stubs inside dwarves-tune-graph (walk.rs, srcgraph/) stay the owner's and are not used here.
10.3 Dependency sources from Holger
The walk covers third-party crates because the room holds them: the driver compiles and dumps every crate a program links (RUSTC_WRAPPER, §3.1). Their exact sources come from a registry. With MIMIR_CRATE_MIRROR set to a cargo sparse index that mirrors crates.io (Holger's pull-through sparse+<holger>/production/crates-io/, or the dev pair's sparse+http://127.0.0.1:18444/cache/index/), they come from that mirror and never from the network (crates/mimir-ingest/src/crate_mirror.rs):
| setting | effect |
MIMIR_CRATE_MIRROR=sparse+… |
DriverDumper::with_env_crate_mirror writes <target dir>/mimir-cargo-home/config.toml ([registries.holger], [source.crates-io] replace-with = "holger"); every cargo the dumper starts (clean, unit graph, the dump, the super build's entries) gets CARGO_HOME there |
MIMIR_CRATE_MIRROR_TOKEN_ENV=<VAR> |
the read token is taken from <VAR> and handed to cargo as CARGO_REGISTRIES_HOLGER_TOKEN (credential-provider = "cargo:token"); it never lands in a file or an argv |
MIMIR_CRATE_MIRROR_CAINFO=<file> |
[http] cainfo for a mirror behind a private CA |
Before the dump, cargo fetch --locked gets every Cargo.lock entry from the mirror, so a crate the mirror cannot serve fails there, by name. Holger is read through the registry door it already serves (the sparse index and the download). Cargo checks each .crate against the lockfile's checksum. A repo's own .cargo/config.toml (a vendored source) still wins. The code room's dumpers (src/code_room/consumer_loop.rs) and the consume example take the mirror from the environment.
Proof (2026-11-04, Holger's scan worker as in §10.2, Holger's dev pair with the rust-remote download fix): 758 registry crates came from Holger's /cache and none from crates.io; the max is 118 calls (77 direct), the scan probe's 23 and the job probe's 30 measured calls are all inside it, 0 gaps; 25 of the 118 are made in a registry crate Holger served (libc 0.2.191, rustix: io_uring_setup, landlock_create_ruleset, epoll_*, futex, mmap, …).
11. Consumers outside nornir
| consumer | reads | where |
dwarves cargo lens graph-package |
the driver's *.edges.arrow (kind CALLS) of a dump it runs or is given; never the lake |
dwarves crates/dwarves/src/lens_graph.rs |
| dwarves-gui | CodeRoom.Answer and the Mimir.* lens services through the forge |
dwarves-gui/src/room.rs, mimir_lens.rs |
| facett | plain node/edge rows handed to CoderoomPane, Graph3D, WarehouseDeck; no Mímir reader of its own |
facett facett-coderoom-view/src/lib.rs |
Next (planned, not built)
- A second producer: a universal SCIP import of any
scip-*indexer'sindex.scipinto the samecode_nodes/code_edgestables, same ids. - A viewer trait in facett (
crates,symbols,calls,span,text) with a znippy reader and aCodeRoom.Answerreader behind it.