Repository navigation
Crate fan-out five-whys: affected crates 49.6/85 per PR (READERS 50 + dev-edge cycle) #5842
Description
Crate fan-out five-whys (read-only; cargo metadata --no-deps --offline, no build)
Method: 85 packages, 257 workspace-internal edges (190 normal, 37 build, 30 dev). Transitive reverse-dependency closure per crate over all edge kinds (script: awk over cargo metadata edges; scratch /mnt/nvme-raid0/tmp/w5382-fan.awk).
Why 1 - affected crates 49.6/85 per PR. scripts/affected_set.sh unions (a) the reverse closure of the changed crate and (b) READERS, which is 50 crates added to every non-ALL set. Mean reverse closure alone is 20.2 crates (over 77 crates with edges); READERS is the larger term.
Why 2 - the closure is large because of a dev-dependency cycle. aprender-core, aprender-compute, aprender-serve and aprender-train each reach 44 crates, because of dev edges (aprender-compute -> aprender-core (dev), aprender-core -> aprender-train (dev), ...) which make one big strongly connected group. Ignoring dev edges the mean closure falls from 20.2 to 11.1.
Why 3 - READERS is large because any crate that can read another's files at run time (CARGO_MANIFEST_DIR parents, include_str of ../..) must be listed (#5802 guard).
Why 4 (hypothesis, not measured) - those readers read because tests scan the tree (e.g. aprender-core falsification scans every crate's src).
Why 5 (hypothesis, not measured) - tree-scanning tests are in the per-crate lib/test targets, not in a separate scan job keyed to the files they read.
Top 10 by transitive fan-in (crates affected when it changes, incl. dev edges)
| closure | direct | crate |
|---|---|---|
| 57 | 11 | aprender-contracts-macros |
| 55 | 20 | aprender-contracts |
| 53 | 27 | aprender-build-sha |
| 53 | 13 | aprender-present-core |
| 48 | 1 | aprender-present-test-macros |
| 47 | 2 | aprender-present-test |
| 46 | 2 | aprender-rand |
| 46 | 11 | aprender-common |
| 46 | 10 | aprender-present-terminal |
| 45 | 5 | aprender-simulate |
| (aprender-quant, aprender-profile-core, apr-format, aprender-test-derive, aprender-sparse: 45. aprender-core/compute/serve/train: 44 each.) |
Cut proposal, ranked by mean affected-crates saved per changed crate (single edge removed, recomputed)
| saved | edge | kind | move |
|---|---|---|---|
| 4.52 | aprender-test-lib -> aprender-compute | normal | make the compute use in test-lib a feature or split a compute-free test-lib-core |
| 3.53 | aprender-compute -> aprender-core | dev | move those dev tests to aprender-core or an integration crate |
| 2.49 | aprender-gpu -> aprender-test-lib | dev | gpu tests use test-lib-core |
| 1.99 | aprender-zram-core -> aprender-gpu | normal | feature-gate the gpu path |
| 1.60 | aprender-core -> aprender-train | dev | move the train-using tests to aprender-train |
| 1.23 | aprender-qa-runner -> aprender-test-lib | normal | use test-lib-core |
| 1.19 | aprender-simulate -> aprender-present-test | dev | move test helper |
| Edges are measured one at a time; savings are not additive (removing the first two cuts the cycle). Biggest single lever outside edges: shrink READERS (50) by moving tree-scanning tests to one scan job, which removes ~50 from every PR's set. | |||
| Caveat: affected set is a test-selection superset; cutting a dev edge changes what tests run for a change, so each cut needs the owning crate's tests moved, not deleted. |
Activity
noahgift commentedon Oct 22, 2026
tracked in #3997