The dead-pub audit: 411 items, 2 dead, ~2 100 lines of over-visibility
Snapshot db64923, 2026-10-01. Tool: tools/dead_pub_audit.py (stdlib only,
one pass, no cargo). Nothing was deleted.
The headline the owner asked for
Section titled “The headline the owner asked for”“Cut hard, but cut on evidence.” This is the evidence, and the answer is not the
answer anyone wanted: there is almost nothing dead. Of 411 pub items across
our 23 crates, 2 are dead outright — 60 lines. The real finding is a
different one, and it is worth more than the deletion would have been:
| verdict | items | lines | what it means |
|---|---|---|---|
live — a caller outside its own file |
287 | 7 210 | nothing to do |
needs-eyes — the name is shared by another item |
32 | 292 | cannot be called dead by name search; see §4 |
demote — reached only from its own file or a test |
87 | 2 085 | pub is over-visible; the body is live. The cut here is pub → pub(crate), ~60 characters |
cfg-only — no caller in the default feature set |
2 | 21 | a note, not a death (NOISE (c)) |
dead-documented |
1 | 12 | named in a doc, called by nothing |
DEAD |
2 | 60 | no code caller, no doc mention, no test |
The scale-down of “масштабное урезание”: the honest number is 60 lines of dead
code, not thousands. Everything else is either load-bearing or a visibility
label. §7 says where the mass actually is — and it is not in pub items.
Method, and the four ways it can be wrong
Section titled “Method, and the four ways it can be wrong”tools/dead_pub_audit.py finds every ^pub fn|struct|enum|trait|const at
column 0 (top-level API only; impl-block methods are indented and are counted
through the type or trait name that carries them), then looks for that name in
every .rs file in the repo — the 6 workspace crates and the 20 library
crates, plus vendor/dormouse-fused/{bench,benches,tools} and our own tools/.
vendor/cubecl-fix and vendor/cubek-fix define none of ours but are read as
callers. One name-search pass per file; ~5 s cold.
A mention is split three ways, because the three answers are three different verdicts:
- in another file, in code → a real caller (
calls) - in its own defining file, in code →
pubis over-visible, the body is live (demote). This split matters: it is the difference between “delete 439 lines” and “delete the wordpub”. The first version of this script got it wrong and reportedbidiag_host— 439 lines of Golub-Kahan bidiagonalization — as dead, whenhost_svd.rs:52calls it. - in a comment → documented, not called (
dead-documented)
A self-use below the file’s first #[cfg(test)] is counted as a test use, so
“only the tests reach it” is a visible column and not silently demote.
One scope fact worth its own line: the doc column reads .rs comments only.
A name documented in a docs/**.md file is invisible to it — which is why
cholesky_host_par reads doc = 0 although two other audits written the same
day name it (§1). A .md mention is corroboration, never a caller.
The four noise classes, named in the script’s header:
- (a) a
pub usere-export counts as a use. Theburn-fusedfacade (vendor/dormouse-fused/burn-fused/src/lib.rs, 60 lines, generated bytools/gen_facade.py) re-exports all 20 crates. Nothing in either manifest depends on it — the facade is a CI artifact, not a product dependency, so for our purposes it is not a caller either way. It islibrary-api, not a candidate. - (b) trait methods are reached through the trait name. A
pub traitwhose every method has zero direct mentions is normal and is not reported dead: the trait itself is the item. - (c)
#[cfg(feature = …)]is a note, not a death.cfg-onlymeans “no caller under the default feature set”. Two items are in that class (§6). - (d) a shared name can never be called dead.
new,forward,seam_countsappear in several items; every one of them isneeds-eyes, neverDEAD. 32 items, listed in §4.
Two more limits, both erring toward not deleting: cfg_gated stops at the
first blank line when walking up to an enclosing mod, and item_extent
brace-balances without parsing string literals. The first makes a gated item read
as live; the second under-counts. Seven probes were checked by hand and all seven
extents match the closing brace exactly.
1. The dead: 2 items, 60 lines
Section titled “1. The dead: 2 items, 60 lines”| item | file:line | lines | why it is dead |
|---|---|---|---|
burn_sct::qr::cholesky_host_par |
vendor/dormouse-fused/crates/burn-sct/src/qr.rs:562 |
49 | no caller anywhere. Its serial f32 twin cholesky_host (same file, :536, pub(crate)) IS called — qr_cuda.rs:578 — so the f64 threaded variant lost its consumer and kept its name. Cross-validated: two independent same-day audits reached the same verdict — docs/research/2026-10-01-spectral-inventory.md:78 (“(d) DEAD: pub, zero callers”) and docs/reviews/spectral-stack-audit-2026-10-01.md:62 |
burn_sct::qr_cuda::cube_of_int |
vendor/dormouse-fused/crates/burn-sct/src/qr_cuda.rs:78 |
11 | no caller anywhere. The sibling cube_of (:55) has 147 callers in the same file. cube_of_int is the int-tensor variant of a helper nobody needed at int |
Both are in burn-sct, whose whole surface is library API (§5), so the verdict
is delete rather than demote — but see §8 for why one of them is worth a
second reader: cholesky_host_par is the only unsafe block in the audit’s top
10.
2. Dead-but-documented: 1 item, 12 lines
Section titled “2. Dead-but-documented: 1 item, 12 lines”DELETED 2026-10-01 — function and doc line together, in the config-seams
lane (docs/reviews/config-seams-2026-10-01.md); grep train_eval_split crates/ tools/ is 0. The record below is the finding as made.
dormouse_data::train_eval_split (crates/dormouse-data/src/lib.rs:192) is
called by nothing and mentioned exactly once, at lib.rs:16:
//! - [`train_eval_split`] returns a stable held-out tail so eval sees unseenThat sentence is false about our own trainer. The trainer takes an explicit
--eval file and streams it separately (dormouse-data/src/lib.rs:577, “Stream
over an explicit file list (e.g. a held-out split)”), so the crate-level doc
advertises a function nothing calls and a mechanism the trainer does not use.
This is ADR-0019’s shape in prose: the reader is told an arm ran when it did
not. Verdict: delete the function and the doc line together — the doc line
is the more valuable half of the deletion, because it is the thing that is wrong.
3. demote: 87 items, 2 085 lines — the actual finding
Section titled “3. demote: 87 items, 2 085 lines — the actual finding”Not dead; over-visible. pub on an item only its own file reaches says “this is
API” when it is not. The cut is one word each, so this row is a hygiene
answer, not a size answer. The top of it:
| item | file:line | lines | reached from | verdict |
|---|---|---|---|---|
burn_sct::bidiag_host |
host_svd.rs:168 |
439 | host_svd.rs:52 (same file) |
pub(crate) |
burn_gdn2::chunk_wy_forward_loop |
forward.rs:350 |
297 | forward.rs:154 + 2 tests |
pub(crate) — but see §8 |
burn_gdn2::chunk_wy_forward_batched |
forward.rs:195 |
132 | forward.rs:152 + 2 tests |
pub(crate) |
burn_sct::dbdsqr |
host_svd.rs:612 |
94 | host_svd.rs:60 |
pub(crate) |
burn_attnres::depth_attend_backward_cuda |
fused_attnres.rs:481 |
93 | 3× same file | pub(crate) |
burn_attnres::two_phase_attend |
lib.rs:618 |
91 | tests only (lib.rs:721,733, below #[cfg(test)] at :710) |
pub(crate) |
burn_spectral::polar_orthogonalize |
lib.rs:246 |
62 | 11 in-file + 9 in-file tests | keep pub — the doc calls it out as an oracle seam |
burn_muon_plus::ns_combine_cuda |
fused_kernels.rs:89 |
44 | 3× in-file tests | already documented dead — see §5 |
burn_spectral::polar_orthogonalize_batched |
lib.rs:316 |
43 | lib.rs:374 |
pub(crate) |
burn_kda::apply_rope |
lib.rs:259 |
37 | 2 in-file + 9 in tests/kda_rope.rs |
keep pub — the doc says why: “Public because it is the oracle’s seam” |
Two of the top ten are already justified in their own doc comments
(apply_rope, polar_orthogonalize). That is the library API working as
intended, and it is the reason the demote row is not a delete list.
4. needs-eyes: 32 items, 292 lines — regex cannot decide these
Section titled “4. needs-eyes: 32 items, 292 lines — regex cannot decide these”A name shared with another item makes the count an upper bound belonging to all
of them, so none is ever called dead. The heavy ones: seam_counts (6 items),
reset_seam_counts (6), ternarize (2), quant_format (2), pool_stats (2),
init_pools (2), memory_cleanup (2), kda_seam_counts (2), eggroll_mutate
(2), note (2), calls (2), reset (2).
Nearly all of these are counters or resets — a seam function, i.e. code whose
only job is to be counted (the exceptions are ternarize and quant_format,
duplicated quantizer names, not seam counters). The pub is deliberate. Do not
read this row as a finding; it is the list of names a name-based audit cannot
resolve, and a
type-based one (cargo +nightly udeps / -Zunused-crate-dependencies) would.
5. library-api: legitimately “dead” inside this repo
Section titled “5. library-api: legitimately “dead” inside this repo”A technology library’s pub is a promise to a future caller, not a claim about
today’s call graph. These are not deletion candidates and the audit says so:
burn-muon-plus::ns_combine_cuda(fused_kernels.rs:89, 44 lines) — the crate’s own module doc already states it (burn-muon-plus/src/lib.rs:53): “ns_combine_cudahas no production caller: its only one was the factored NS branch inMuonPlus::orthogonalize, deleted as unsatisfiable … It is kept because its own test in this module still pins the kernel against the tensor-op expression it computes.” This is the precedent for the wholelibrary-apiclass: dead in production, pinned by a test, kept on purpose, and said so where a reader will find it. Any future deletion in this repo should either cite this shape or give a better one.- The
burn-fusedfacade — 60 generated lines, nothing depends on it, and that is correct: it is whattools/gen_facade.py --checkdiffs in CI. burn-es,burn-parcae,burn-ptrn,burn-eggroll— whole crates with no manifest naming them (§7).
6. cfg-only: 2 items, 21 lines — notes, not deaths
Section titled “6. cfg-only: 2 items, 21 lines — notes, not deaths”| item | file:line | the gate | reading |
|---|---|---|---|
dormouse_train::cubecl_client |
crates/dormouse-train/src/lib.rs:319 |
#[cfg(feature = "cuda")] |
parked, not dead. Its own doc: “factored out because the graph seam needs it too and two copies of a backend downcast is how they drift.” A sibling worktree (wt/cuda-graph) is building the consumer. Do not delete — the doc already says what would break |
burn_dspark::accept_rate_loss |
vendor/dormouse-fused/crates/burn-dspark/src/lib.rs:309 |
#[cfg(feature = "training")] |
training is enabled — crates/dormouse-core/Cargo.toml:23 requests it. So the gate is open and there is still no caller. The nearest verdict is demote/test-pin, but the module doc at lib.rs:7 claims it is “matched against the official …” reference, which is the claim a reader would check. Reported, not judged |
7. Where the mass actually is
Section titled “7. Where the mass actually is”The pub-item cut is 60 lines. The unused code is measured differently, and it
is not small:
Four library crates, 1 388 lines of src/, that no product manifest names
as a dependency. The only manifest that names them is the burn-fused
facade’s own (vendor/dormouse-fused/burn-fused/Cargo.toml:85-95), and the
facade is the CI artifact above, not a consumer:
| crate | src/ lines |
referenced by another crate |
|---|---|---|
burn-ptrn |
399 | nothing |
burn-es |
345 | nothing |
burn-eggroll |
327 | nothing (one name-only mention, in burn-es) |
burn-parcae |
317 | nothing |
That is 23× the dead-pub figure, and it is a whole-crate decision, not an
item decision. .bulba/plan.md’s question 4 (“the unwired library, start
deleting now?”) is the right question; this audit is one line of its answer.
A fifth, burn-fused itself (60 lines), is a CI artifact by design.
burn-sct is the other concentration: 593 of its lines sit under non-live items,
533 of them in host_svd.rs — a 745-line vendored LAPACK transcription. It is a
library crate with a live CUDA QR consumer, so this is library-api again, but
it is the one crate where a reader should look twice.
8. Verdicts on the top 10 by lines, checked by eye
Section titled “8. Verdicts on the top 10 by lines, checked by eye”Each was read, not just counted. delete means “remove the item”; demote means
“pub → pub(crate), body stays”.
| # | item | lines | verdict | why |
|---|---|---|---|---|
| 1 | burn_sct::bidiag_host |
439 | demote | called at host_svd.rs:52 from svd_host. A Golub-Kahan bidiagonalization with 439 lines and one caller in the same file. Not dead; mislabelled |
| 2 | burn_gdn2::chunk_wy_forward_loop |
297 | demote, blocked | called at forward.rs:154, and tests/ops_batched_diff.rs:367 imports it. pub is honest — an A/B seam between the loop and the batched arm. Do not touch without the owner’s A/B decision |
| 3 | burn_gdn2::chunk_wy_forward_batched |
132 | demote | same pair, same reason. The two together are the loop-vs-batched A/B, which is an open experiment, not dead code |
| 4 | burn_sct::dbdsqr |
94 | demote | called at host_svd.rs:60. LAPACK dbdsqr shifted-QR iteration, vendored |
| 5 | burn_attnres::depth_attend_backward_cuda |
93 | demote | 3 in-file callers. AGENTS.md §2.2 records AttnRes as wired-but-unwired-for-Backward-Block; the file is load-bearing |
| 6 | burn_attnres::two_phase_attend |
91 | demote | reached only by two tests below lib.rs:710. The one demote in the top ten that is a real visibility bug: a 91-line public API no production code calls |
| 7 | burn_rmsnorm::MIN_FUSED_D |
1 | keep | Not dead: MIN_FUSED_D is the documented refusal threshold from the 2026-09-30 RMSNorm finding (AGENTS.md §3.3). It is a named constant precisely so the threshold is readable. It reads demote — one self-use inside the cuda module (fused.rs:215) plus 7 test uses — not a deletion candidate in any reading |
| 8 | burn_spectral::polar_orthogonalize |
62 | keep | 11 in-file + 9 test uses, and lib.rs:1641 names it as the reference retract is pinned against |
| 9 | burn_sct::cholesky_host_par |
49 | delete | 0 callers. And it is the only item in the top ten containing raw-pointer unsafe (qr.rs:588-602, disjoint-row-slicing across std::thread::scope, hand-rolled Send-ness argument). Deleting it removes ~30 lines of unsafe from a crate that has one other use of it. That is the strongest single argument in this report, and it is an argument about unsafe, not about line count |
| 10 | burn_kda::apply_rope |
37 | keep | 9 uses in tests/kda_rope.rs, and the doc says why: “Public because it is the oracle’s seam” — it is compared against FLA’s rotary_embedding_ref. §1.4’s evidence rule in the code |
Net of the top ten: 1 delete (49 lines, and it is the unsafe one), 5 demote,
3 keep, 1 blocked on an open A/B. Not one of the ten is the “large cut” anyone
imagined, and the two largest (1 and 2) are A/B seams and a vendored algorithm
respectively.
9. What this audit does NOT establish
Section titled “9. What this audit does NOT establish”- It is a name search, not a type analysis.
cargo udepsresolves paths; this does not. Apub fnreached only through a macro expansion, a trait object, or a#[cfg]this script does not parse reads as dead. Thedemotesplit exists because that failure mode was observed and fixed once already (§3, item 1). impl-block methods are out of scope by construction. The surface a type-based tool would find is not measured here.- 32
needs-eyesitems are unresolved, not cleared (§4). - It says nothing about dead code with a live caller — a function called from one place that itself is dead. That is a reachability question, and this is not the instrument for it.
- Snapshot
db64923. Active lanes are changing these files. Re-runpython3 tools/dead_pub_audit.pyand diff; the columns are stable for exactly that purpose.
The one-line answer
Section titled “The one-line answer”60 lines of dead pub in a repo that looks like it has thousands, and the real
unused mass — 1 388 lines across four whole library crates — is not visible to a
pub-item audit at all. Cut the 60, demote the 87 pubs, and decide the four
crates as crates.