Fitting the node kernel: the process
This is the step-by-step way to fit a tunnr node's kernel to the programs it runs, using Heimdall's evidence and Build Thing. The kernel keeps every option the evidence needs, and it drops an option only when coverage shows the code never ran and a full rerun stays green. Each drop has a receipt. Nothing is typed by hand.
The reference for every file, schema and verb is kernel-tooling.md. The seccomp side (how a program's own filter and the node's floor are made) is in tunnr's idiot guide and node-floors.md. State of the code: heimdall main d568179, tunnr main 2026-11-08.
The rule
Let R be the calls the row's programs made (Heimdall's probe), P the calls their code can reach (Mímir's possible sets), and opts(c) the kernel options that gate call c in the row's kernel tree (Build Thing's syscall map). Let N_rt be the options Heimdall's runner needs (heimdall kernel needs --json).
Need = opts(R) ∪ N_rt generated as CONFIG_X=y rows
Keep = opts(R ∪ P) ∪ N_rt never offered as a veto
veto(X) ⇔ X ∉ Keep
∧ X ∉ protect.list
∧ cov(X) = 0 no code of X ran during the row's full suite
∧ suite(kernel − X) = green
The possible set protects but never adds: a call no run made does not become a =y row, but its options can never be dropped. Coverage is per fragment: a coverage report counts only for the merged fragment whose digest it names.
Step by step
All commands run in the toolchain container. <row> is a node row, for example rusternetes-node.
- Measure the programs. Record each program's calls on the probe medium:
scripts/kernel-suite.sh <row> <suite> heimdall <out>, and approve the profiles (scripts/heimdall-approve.py). Pods:heimdall profile probe-oci. The PID 1 tree:scripts/kernel-suite.sh <row> bridge log(heimdall profile probe-log). Details: SECCOMP.md. - Trace the code.
heimdall graph src <workspace> --bin <program> --out <dir>writes<program>.possible.json(P). Commit it with itssource.json. - Save the join.
tunnr-build-thing kernel needs <row> --savewrites.nornir/profiles/<row>/kernel-needs.json: every measured call joined to the options that gate it. tunnr compiles the file in (crates/tunnr-build-thing/src/joined.rs), so the row'sCONFIG_X=yrows are generated from it. - Add the runner's needs. For a row that runs Heimdall jobs:
heimdall kernel needs --json > .nornir/kernel-runtime-needs/<name>/heimdall.json, thentunnr-build-thing kernel requires-from-needs <row> --needs <file>. - Check.
cargo xtask evidence <row> --checkrefuses[stale-needs],[kernel-unexplained]and[hand-typed-kernel-row].tunnr-build-thing preflight --strictandmeasure gaterefuse[stale-join],[kernel-lacks-generated]and any veto line without a matching receipt. - Measure the kernel.
tunnr-build-thing kernel coverage <row> --run <suite>composes the row's media with the gcov probe (kernel-probe <row> --probe gcovcomposes the same medium on its own), runs the row's full suite on KVM and writes.nornir/kernel-coverage/<row>/<sha12>.json. Run the failure paths too (the protect list covers what a green suite cannot reach: block errors, watchdog, NVMe reset). - Pick and drop.
tunnr-build-thing kernel candidates <row>lists veto-ready options;kernel what-if <row> --drop CONFIG_Xshows what a drop takes away. Thentunnr-build-thing kernel veto <row> CONFIG_X --run <suite>: the full suite runs again on the vetoed kernel. Green writes an applied receipt (.nornir/kernel-vetoes/<row>/receipts/<date>-CONFIG_X.json) and the list line; red writes a refused receipt and changes nothing. One option per run. - Build.
dwarves buildthing <row>. The vetoes land asCONFIG_X=nrows in the next merged fragment;tunnr-build-thing kernel vetoes <row>shows each line BACKED or UNBACKED.
Any change to the fragment (a new generated row, a new preset line) makes the coverage stale: run step 6 again before the next veto.
Where tunnr stands (2026-11-08)
| Item | State |
| Kernel row | tunnr-kernel-k8s 6.12.104, x86_64 |
Join, rusternetes-node |
saved: 169 measured calls → 14 options |
Join, rusternetes-node-aya |
saved: 18 calls → 5 options |
| Runner needs | .nornir/kernel-runtime-needs/tunnr-kernel-sandbox/heimdall.json, on the sandbox row |
Coverage, rusternetes-node |
2026-11-04, suite bridge: 992 symbols, 309 ran, 54 never ran, 629 not measured |
Coverage, rusternetes-node-aya |
suite aya: 1028 symbols, 322 ran, 64 never ran |
| Vetoes | none active. CONFIG_MOUSE_PS2_BYD was dropped on 2026-11-06 when CONFIG_IO_URING changed the fragment; it comes back only through a new coverage run and veto |
| Protect list | .nornir/kernel-vetoes/rusternetes-node/protect.list |
Next for tunnr: run coverage on the current fragment (step 6), then the veto loop (step 7).
Who does what
| Part | Home | Licence |
The probe, the profiles, the runner's needs, heimdall graph src |
heimdall | AGPL-3.0 |
The possible set (cargo-mimir-dump, mimir-exec) |
nornir (Mímir) | |
| The join, the fragment, coverage, vetoes, receipts | edda nornir-build-thing, tunnr tunnr-build-thing |
MIT |
| The schemas of every file | edda nordisk-kernel-evidence |
MIT |
The homes share files, never code: Build Thing never links Heimdall.