"Audit accumulated technical debt — stale markers, dead code, duplication, magic numbers, stub impls, doc rot, oversized files"
Recursos
1Instal·la
npx skillscat add matiaszanolli/byroredux/claude-commands-audit-tech-debt Instal·la des del registre de SkillsCat.
Tech-Debt Audit
Audit ByroRedux for accumulated technical debt: code that compiles, passes tests and ships, but raises the
cost of every future change. Correctness bugs belong to other audits; this one hunts decay since the last
cleanup pass.
Every dimension below is a DISCOVERY RECIPE, not a finding list. Instances churn between audits, so each
dimension hands you a command that enumerates current instances plus a triage rule. There is no hardcoded
instance list here on purpose — re-run the recipe and report what it surfaces today. Where a cargo test /
CI gate already enforces an invariant, the dimension names the guard and aims at what it cannot see.
Architecture: Orchestrator. Each dimension runs as a Task agent (max 3 concurrent).
See .claude/commands/_audit-common.md for layout, crate roster, methodology, dedup, severity and finding
format. Young code has had the fewest sweeps — find it withgit log --diff-filter=A --since=<last-report-date> --name-only --format= -- 'crates/*/Cargo.toml' 'tools/*/Cargo.toml'
plus the crates the last report never names (for c in crates/*/; do grep -q "$c" <last-report> || echo "$c"; done;
the 2026-10-08 report still named none of sdk, mod-runtime, menuxml, save, hkx, spt, pex,sfmaterial, audio, debug-ui, game-detect — 21 crates in all — nor three of the four tools/). File real findings there; do not
just note the crate is young. crates/cxx-bridge and crates/platform are deliberate placeholders owned here:
check they have not grown a second job or silent consumers, not that they are small.
Parameters (from $ARGUMENTS)
--focus <dimensions>: comma-separated dimension numbers (e.g.1,3,5). Default: all 9.--depth shallow|deep:shallow= surface counts + worst offenders;deep= per-instance triage with a concrete fix proposal. Defaultdeep.
Extra Per-Finding Fields
- Dimension: one of the 9 below.
- Age (when relevant): commit hash + date the debt landed (
git log -L/git blame). - Effort: trivial (≤30 min) | small (≤2 h) | medium (≤1 day) | large (>1 day, decompose first).
- ID convention:
TD<dim>-<date>-NN(e.g.TD3-2026-09-05-02= Dim 3 Stale Documentation, finding 2 of that report).
Severity for Tech Debt
Tech-debt findings default to LOW (see _audit-severity.md). Promote only on amplification:
| Promotion Trigger | Floor |
|---|---|
| Duplicated logic with divergent bug-fix history (one branch fixed, the other regressed) | MEDIUM |
unimplemented!() / todo!() / panic!("not …") reachable from a shipped CLI flag or smoke test |
MEDIUM |
#[ignore]d test that guards a fix from a closed CRITICAL/HIGH issue |
MEDIUM |
| Stale doc/audit baseline that misled an audit in the last 90 days | MEDIUM |
| Magic number that would silently over/underflow under documented use | HIGH |
Stale GpuCamera/GpuInstance/GpuMaterial size in a doc comment (lockstep-drift bait) |
MEDIUM |
Phase 1: Setup
- Parse
$ARGUMENTS. 2.mkdir -p /tmp/audit/tech-debt. - Dedup baseline:
gh issue list --repo matiaszanolli/ByroRedux --limit 500 --state all --label tech-debt --json number,title,state > /tmp/audit/tech-debt/issues_all.json - Scan
docs/audits/for priorAUDIT_TECH_DEBT_*.md(diff direction, not re-litigation). - Production-LOC helper (Dim 1's subject is production complexity, not file length — a file long from bulk
inline tests is not the debt this dimension hunts). Source the checked-in script and run its self-test first;
a failure means no figure below it can be trusted:
prod_locsource .claude/commands/audit-tech-debt/prod_loc.sh prod_loc_self_test # must print "prod_loc self-test: ok"<file>reports 0 for pure-test files (tests.rs,*_tests.rs, anything undertests/— their#[cfg(test)] modgate lives in the parent) and otherwise total LOC minus every#[cfg(test)]-gated braced
item, counting braces on code only (comments, strings, raw strings and char literals stripped, #4336). - Snapshot totals so the next audit can diff.
tools/is in scope (four workspace binaries);tools/nifskopeis
vendored and pruned:
Measured 2026-10-12 at 0d698d16c (diff direction only, re-run, never quote): markers 24 (15 are{ echo "markers (TODO/FIXME/HACK/XXX/TBD/WIP/KLUDGE): $(grep -RInE '(TODO|FIXME|HACK|XXX|TBD|WIP|KLUDGE)\b' crates byroredux tools --exclude-dir=nifskope | wc -l)" echo "allow(dead_code): $(grep -RInE 'allow\(dead_code\)' crates byroredux tools --exclude-dir=nifskope | wc -l)" echo "unimplemented!/todo!(): $(grep -RInE 'unimplemented!|todo!\(\)' crates byroredux tools --exclude-dir=nifskope | wc -l)" echo "#[ignore] tests: $(grep -RInE '^[[:space:]]*#\[ignore' --include='*.rs' crates byroredux tools --exclude-dir=nifskope | wc -l)" echo "files >2000 production LOC: $(for f in $(find crates byroredux tools -name '*.rs' -not -path 'tools/nifskope/*'); do echo "$(prod_loc "$f")"; done | awk '$1>2000' | wc -l)" echo "test files >2000 total LOC (lower priority, separate bucket): $(find crates byroredux tools -name '*.rs' -not -path 'tools/nifskope/*' -exec wc -l {} + | awk '$1>2000 && $2!="total"' | wc -l)" } > /tmp/audit/tech-debt/baseline.txtXXXXfalse positives, 2 the
FO4HACKFourCC — Dim 5),allow(dead_code)44 (45 on 2026-10-10; the 11 added since 2026-10-08 arecfg(test)
TypeId-only markers incrates/core/src/ecs/lock_tracker.rs, c5113f0d9 — not debt),unimplemented!/todo!()0 (a
fresh hit is notable),#[ignore]299 (287 on 2026-10-10; tools-inclusive — earlier reports scoped tocrates+byroredux
read lower),
production >2000 LOC: 4 (shader_constants_data.rsis a data table, Dim 1;byroredux/src/components.rs;crates/scripting/src/fragment/effects.rs;byroredux/src/save_io.rs, new — it crossed to 2011.byroredux/src/env_translate/
left the list: it was one file at 1881 → 2186 across 2026-10-05..11 on the #5374/#5388/#5423/#5424 climate/LOD fixes and #5584 split it
per concern intolod/climate/water/sky_weather/fallback, none over 700 production LOC; watch-list within 5%:crates/nif/src/import/types.rs(1997),crates/audio/src/lib.rs,crates/plugin/src/esm/cell/mod.rs,crates/scripting/src/translate/effects.rs,crates/scripting/examples/mq101_conformance.rs), test-heavy >2000: 77.
A raw whole-repo grep for#[ignore]also matches markdown prose — keep--include='*.rs'.
Phase 2: Dimension Agents
Ordered by debt impact: complexity and duplication compound across every edit; doc/audit rot misdirects the next
audit; markers and dead code are cheap. Recent yield (grep -h '\*\*Dimension\*\*' docs/audits/AUDIT_TECH_DEBT_*.md):
Dims 4, 3, 1, 8 dominate (then 2, 9); 5 and 6 rarely surface real debt. Each agent writes /tmp/audit/tech-debt/dim_<N>.md.
Dimension 1: File / Function / Module Complexity
Paths: all .rs under crates/, byroredux/, tools/
First step: the two-bucket command below
An oversized file taxes every edit, review and merge. Threshold is 2000 production LOC. Two buckets:
# Primary — the dimension's actual subject. File real findings from this.
for f in $(find crates byroredux tools -name '*.rs' -not -path 'tools/nifskope/*'); do
p=$(prod_loc "$f"); [ "$p" -gt 2000 ] && echo -e "$p\t$f"
done | sort -rn
# Secondary — test-heavy files, report but do not auto-file: escalate one only if its OWN prod_loc also crosses 2000.
find crates byroredux tools -name '*.rs' -not -path 'tools/nifskope/*' -exec wc -l {} + | awk '$1>2000 && $2!="total"' | sort -rnThe recipe output is authoritative. A file that once split can re-cross (a previously-split file that grew back is a
live finding); a file that dips under by incidental shrinkage is still a candidate — only an actual split removes one;
and files within ~5% of the line (check the snapshot) are worth naming as watch-list rows. Function-level splits inside
a file and file-level splits are independent signals — a register_*_systems / phase-helper extraction does not move
its host file across the line.
Per file, propose a split AXIS by responsibility, chosen after reading the file's internal structure — never from a
name or a tag. Precedent: a metadata enum tag (ExtenderFamily) touching 30 of 3759 lines was not the seam; the real
axis was the four-layer service stack (routes → declarations → source aliases → runtime adapters) with one service
holding over half the lines (#3851). Splits that worked: Vulkan context/ and volumetrics by
construct-vs-record-vs-teardown; boot.rs into one file per registration stage; runtime.rs into one file perimpl <wit>::Host block. Data tables (FourCC → id maps, shader_constants_data.rs) want a static table or
generation, not a split. Vulkan-recording splits are render-pass-adjacent — read
feedback_speculative_vulkan_fixes before proposing barrier/order changes.
Also flag: functions >200 LOC (propose extraction); match arms >50 cases (want a lookup table); nesting depth >5;
a mod.rs / lib.rs with >20 pub use (two jobs). cargo +nightly clippy --all-targets -- -W clippy::cognitive_complexity
if available, else inspect the worst offenders.
Dimension 2: Logic Duplication
Paths: sibling-file families under crates/nif/src/blocks/, crates/plugin/src/esm/records/, crates/renderer/src/vulkan/, byroredux/src/cell_loader/, byroredux/src/systems/
First step: ls crates/nif/src/blocks/*.rs crates/plugin/src/esm/records/*.rs crates/plugin/src/esm/records/*/*.rs crates/renderer/src/vulkan/*.rs byroredux/src/cell_loader/*.rs, then read two siblings side by side
CLAUDE.md global policy: improve existing code, never duplicate logic. Every finding names a concrete
consolidation site (an existing helper to extend, or the new one and its callers).
Look for: block-parser scaffolding (header → field → fixup) repeated across crates/nif/src/blocks/; texture-upload
chains (BC1/BC3/BC5/RGBA) and image-layout barrier sequences repeated per pass in crates/renderer/src/vulkan/
(vulkan/image.rs GpuImage and the shared barrier helpers are the consolidation targets — a pass that still
hand-rolls create/bind/destroy is a candidate); vk::WriteDescriptorSet builder boilerplate; ESM sub-record parse loops
across crates/plugin/src/esm/records/; AI-procedure systems sharing scaffolding; near-identical per-game HUD/profile
tables; source-scan helpers (production_text, production_text_or_whole, strip_test_modules, count_identifier) have ONE
home, crates/core/src/source_scan.rs (#5100, 655b317c9; #5469, 334458b3f routed the ~40 surviving inline cuts through it) — a
re-copied cut in a test module is a regression; no_source_scan_cuts_with_the_weak_cfg_test_needle
(byroredux/src/workspace_hygiene_tests.rs) fails a new weak #[cfg(test)] find/split outside its allowlist. The Z-up→Y-up conversion has one home, crates/core/src/math/coord.rs (zup_to_yup_pos,zup_to_yup_quat_wxyz); re-exports elsewhere are not leaks — a genuine reimplementation would live outside that file.
Dimension 3: Stale Documentation & Comments
Paths: docs/, ROADMAP.md, HISTORY.md, README.md, CLAUDE.md, doc comments across the tree
First step: .claude/commands/_audit-validate.sh
Doc rot misleads the next reader and the next audit. Run the gate first: _audit-validate.sh resolves every
backticked path in the audit skills AND docs/engine/*.md against the tree (fatal on STALE) and lists backticked
symbols found in no tracked .rs file (advisory — clear it, do not learn to scroll past it). STALE refs are
auto-eligible findings (trivial). Guards that already police a class — aim at what they cannot see:
- GPU-struct sizes:
gpu_material_size_claims(crates/renderer/src/vulkan/material_tests.rs) scanscrates,byroredux,tools,docs/engine,.claude/commandsand the top-level status docs for a stale byte count of every
size-pinned struct —GpuMaterial,GpuLight,GpuTerrainTile,GpuInstance,GpuCamerasince #5203
(pinned_sizes(); plusbindings_glsl_states_the_real_struct_size). It CANNOT seeVertex::SIZE(a size written
without the type name) orGpuWaterParams-class structs outsidepinned_sizes()— cross-check those against the
layout tests, never the prose:grep -rn "fn gpu_.*_is_[0-9]\+_bytes\|size_of::<Gpu" crates/renderer/src/vulkan/. A GPU-size claim found stale in
prose is MEDIUM (severity table). - Deleted
Material::classify_pbr:no_source_file_frames_the_deleted_classify_pbr_as_live
(byroredux/src/workspace_hygiene_tests.rs) fails a doc that names it as live. The survivors are the free fnclassify_pbr_keywordandMaterial::resolve_pbr. - Beyond the guards, sweep: doc comments naming renamed/deleted symbols (
git log --diff-filter=D --since=<last>then
grep each deleted name); ROADMAP.md milestones "in progress" whose issues are closed (or vice versa) — cross-checkgit log/gh issue;docs/feature-matrix.mdrows against the crate that implements them (git log --grep M45,
…) — it is a status floor, so flag any row contradicting shipped code; HISTORY.md entries referencing reverted work;
README.md /CLAUDE.mdcommand examples whose flags or paths changed; per-game compat numbers indocs/engine/game-compatibility.md
vs ROADMAP.md's matrix (ROADMAP is the single home);docs/legacy/Gamebryo source paths that moved;crates/renderer/shaders/triangle.fragcomments quoting outdated struct sizes. docs/engine/*.mdare the "authoritative" references audits are told to believe (_audit-common.md): beyond the gate's
path/symbol check, sample their numbers and lists against code — stage order and lock order (ecs.md), VRAM/pool figures
(memory-budget.md), shader binding tables (shader-pipeline.md), dependency and crate lists — a doc that misled an audit
in the last 90 days is MEDIUM.- Path convention: a backticked path or snake_case symbol in an audit skill asserts "exists right now"; deleted or
forward-looking names go in italics or plain text (_audit-common.mdPath-Reference Convention).
Dimension 4: Audit-Finding Rot
Paths: .claude/commands/, docs/audits/
First step: .claude/commands/_audit-validate.sh then ls .claude/commands/ docs/audits/ | tail -40
Stale baselines actively misdirect future audits.
- STALE refs the gate prints in other audit skills → Dim 4 findings (trivial); advisory symbols in skills likewise.
- Numeric claims in skills and
_audit-common.md(LOC figures, struct sizes, counts, "all N dimensions") — the gate
cannot see numbers: re-measure a sample (wc -l, prod_loc,grep -c) and flag any off by >20%. Layout-row LOC
drift has been the single most repeated finding here. - "Existing: #NNN" / "open issue" callouts in skills where the issue is now CLOSED:
gh issue view N --json state. - Dimension cross-references between skills ("
/audit-xDim N") that no longer name that dimension. docs/audits/reports older than 90 days whose CRITICAL/HIGH findings have no GitHub trace. Caveat: reports
dated before 2026-06-07 predate/audit-publish, so a missing issue is not evidence a finding is open (#3875,_audit-common.mdDeduplication) — verify against code and say which you checked.- Do NOT flag
.claude/issues/<N>/ISSUE.md"Status: Open" drift: local issue files are immutable snapshots (TD10-001 / #1156);gh issue view <N> --json stateis authoritative.
Dimension 5: Stale Markers (TODO / FIXME / HACK / XXX / TBD)
Paths: crates/, byroredux/, tools/ (not tools/nifskope), crates/renderer/shaders/
First step: the two greps below
grep -RInE '(TODO|FIXME|HACK|XXX|TBD|WIP|KLUDGE)\b' crates byroredux tools --exclude-dir=nifskope
grep -RInE '(TODO|FIXME|HACK|XXX|TBD|WIP|KLUDGE)\b' crates/renderer/shaders/Keep the token list identical in both commands (an asymmetry once hid every shader FIXME, #3877); TBD is in it because
the codebase uses it. tools/ (byro-dbg, byro-launcher, byro-detect, texture-upscale) is first-party and in scope.
Triage each (skip markers <30 days old unless they name a closed issue): git blame for age — over 6 months gets
reported; does it name an issue, and is that issue still open (closed issue + live marker = "marker outlived its driver");
does it name a milestone now complete per ROADMAP.md; a // TODO: implement on a path reachable from a shipped CLI flag
promotes (severity table).
False positives: XXXX, the ESM extended-size sub-record tag (key on comment content — "references the ESM XXXX
escape" — not a file list; reader.rs, cell/wrld.rs, the b"XXXX" test sentinels in records/misc/magic.rs and the
FourCC table doc in sdk/src/compatibility/storage_util/mod.rs all qualify); HACK, the FO4 terminal-record FourCC
(crates/plugin/tests/parse_real_esm.rs); a // FIXME quoting a reference implementation's
own FIXME (crates/bgsm/src/bgem.rs, bs_geometry.rs) documents upstream; a TBD that records an unresolved format
semantic together with its own resolution (the FNV WEAP DNAM arm in crates/plugin/src/esm/records/items.rs) is a
documented unknown, not a stale marker.
Must-not-delete: the third-party attribution block atop crates/renderer/shaders/triangle.frag (GLSL-PathTracer MIT
notice + Burley citation, ~first 30 lines). Flag any edit that strips it — MIT requires the notice to travel with the code.
Dimension 6: Stub & Placeholder Implementations
Paths: crates/, byroredux/, tools/
First step: the two greps below
grep -RInE 'unimplemented!|todo!\(\)|panic!\("not ' crates byroredux tools --exclude-dir=nifskope
grep -RInE '// *(stub|TODO: real|placeholder|not yet)' crates byroredux tools --exclude-dir=nifskopeThe first command should return nothing — any hit is notable. For each: reachable from a shipped CLI flag or smoke test →
MEDIUM; functions returning None / Vec::new() / Default::default() under a stub comment; trait impls with empty bodies
the trait docs say should do work; console commands in byroredux/src/commands/ that no-op or print "TODO".
Production-unreachable features are the yield here: a public builder/system with zero non-test callers whose docs or
ROADMAP say it is wired (a ruleset builder that main never calls; a component nothing inserts). For a candidatename: grep -rnw name crates byroredux tools --include='*.rs' and drop test-only hits. Cross-check per-game ESM record
coverage in crates/plugin/src/esm/records/ against the ROADMAP.md compat matrix (wired vs stubbed).
Dimension 7: Magic Numbers & Hardcoded Constants
Paths: crates/nif/src/blocks/, crates/renderer/, crates/plugin/src/esm/records/
First step: read the version-gate and budget sites; do not regex blindly (most literals are legitimate)
- Bare numeric literals compared against version codes in
crates/nif/src/blocks/→ aNifVersionconstant. - Vulkan
MAX_*/MIN_*hardcoded inline →vk::PhysicalDeviceLimitsor a named constant. - Shader
#defineprovenance: every define is generated fromcrates/renderer/src/shader_constants_data.rs
(include!d byshader_constants.rsandcrates/renderer/build.rs, which emitsshaders/include/shader_constants.glsl);
source-scan tests inshader_constants.rspolice the generated header. The check is "every shader#define/ loop
bound / budget literal that bypasses that file" (lockstep risk HIGH — feedback_shader_struct_sync). - GPU
#[repr(C)]size literals: reference the layout pins (Dim 3 has the recipe and the guards); an inline size
literal that should reference them is a code finding here, a stale prose figure is Dim 3. - Frame/ray/cache budgets (
MAX_TOTAL_BONES,MAX_MATERIALS, …) scattered vs one tunable module; ESM sub-record sizes
hardcoded (if data.len() == 24) → a named constant on the record struct. - Do NOT flag protocol-defined magic: FourCC tags, BSA/NIF/BA2 magic, Vulkan format enums.
Dimension 8: Dead Code & Backwards-Compat Cruft
Paths: crates/, byroredux/, tools/, every Cargo.toml
First step: cargo clippy --workspace --keep-going -- -D warnings (the CI gate) and the greps below
grep -RInE 'allow\(dead_code\)' crates byroredux tools --exclude-dir=nifskope
grep -RInE '#\[deprecated\]|// *removed:|_unused|fn .*_unused' crates byroredux
cargo machete 2>/dev/null || echo "cargo machete not installed — scan Cargo.toml deps vs use stmts"- Unused-dependency gate: CI job
Unused dependenciesrunscargo machete(#3890) — a red run is a finding. Its
blind spots are macro-only and re-export-only use (the job comment says so); the hand scan earns its keep there and on
deps used only under a non-default feature. - Clippy gate (CI job
Test + Check + Clippyrunscargo clippy --workspace --keep-going -- -D warningsplus a
renderer-onlyundocumented_unsafe_blocksre-lint, #5121; the toolchain is pinned at 1.96.0 byrust-toolchain.tomlsince #5308 (b24cb46b6) after floatingstablelet rustc 1.99's chunks_exact_to_as_chunks wave turn the gate red for four days — rustc 1.96 (800802516) and 1.98
(530c9e7aa) raised lints on untouched code too; a toolchain bump is now a deliberate commit, and the distro cargo ignores
the pin; wasmtime 49's MSRV is exactly 1.96.0, 15a6b1d2d, so the pin can rise but not fall). A red gate is a finding:
list each failing lint and file, plus the crates it left unlinted —--keep-goinglints every crate that still
compiles, but a crate red under clippy leaves its dependents unchecked (a redbyroredux-nifskips the bin).
Run--all-targets --keep-goingtoo; test/example-target lints are outside the CI gate — report them as a
lower-priority bucket (the workspace example build itself went red once, the #3894 class, 530c9e7aa). Check every#[allow(clippy::…)]carries a reason comment (the house style fortoo_many_arguments). - Each
#[allow(dead_code)]: called now or still dead? Delete if dead.pub fnin a private module nobody imports (cargo +nightly rustc -p <crate> -- -W unused);mod.rs/lib.rsre-exports with no consumer;_-prefixed params that survived a refactor (delete, do not rename);// removed: …breadcrumbs (delete completely); re-exports of deleted types "for compatibility" (no external consumers
exist — pure rot);#[deprecated]items with no consumers;Cargo.tomlfeature flags with one branch always on/off. - Do NOT flag:
cfg(test)/cfg(debug_assertions)-gated code, FFI boundary functions, or the public API of a
workspace-internal crate a future binary will consume (note it rather than deleting).
Dimension 9: Test Hygiene
Paths: every #[test]/#[ignore] site, .github/workflows/ci.yml, byroredux/tests/
First step: the ignore-triage command below
# All ignores (matches BOTH `#[ignore]` and the reason form `#[ignore = "…"]` — do not tighten to a bare `]`)
grep -RInE '^[[:space:]]*#\[ignore' --include='*.rs' crates byroredux tools
# Ignores whose reason is NOT a data/hardware gate — the triage input
grep -RInE '^[[:space:]]*#\[ignore' --include='*.rs' crates byroredux tools | grep -viE 'game data|installed|\.(bsa|ba2|esm)|BSA|BA2|ESM|audio device|vulkan|gpu|rt-capable|display|opt-in|corpus|real (data|master)|steam|env'- Guards:
workspace_hygiene_tests(byroredux/src/workspace_hygiene_tests.rs) —every_ignore_attribute_carries_a_reason
(a bare#[ignore]fails; the reason text is the triage input),no_tmp_scratch_examples_are_committed(_tmp_*/tmp_*probes) plusno_committed_example_self_describes_as_disposable(module doc opening "throwaway / one-off / TEMP",
#5114),no_test_attribute_is_stacked_on_another, and theclassify_pbrcheck (Dim 3). Confirm they are not themselves#[ignore]d. - Most
#[ignore]s gate Vulkan / game-data / audio tests — not debt. Triage the remainder: does a reason name an issue
(gh issue view N), and if it guards a closed CRITICAL/HIGH fix → MEDIUM. - Tests with only smoke assertions (
assert!(result.is_ok())); commented-out assertions in passing tests; tests thatprintln!without an assert. - Feature gates vs CI lanes: enumerate
[features](grep -A6 '^\[features\]' crates/*/Cargo.toml byroredux/Cargo.toml)
and compare with.github/workflows/ci.yml— non-default states run only where a lane names them (today:coreinspect/saveandscriptingsavevia workspace unification,byroredux-spt --features recon,byroreduxwithoutdebug-server/ withtracing-tracy/ withdhat-heap,byroredux-nif --features dhat-heap). A feature orrequired-featurestarget with no
lane can rot silently (the class #3894 / #4387 / #4390 closed). byroredux/tests/golden_frames.rs(opts into--ignored) — still runnable, golden images current.- Cross-reference "must not regress" lines in other audit skills — each named regression test still exists and is not
#[ignore]d (_audit-validate.shadvisory names symbols that are gone).
Cross-Dimension Dedup
A TODO inside a dead function reports under Dim 8, not also Dim 5. Material doc rot reports under Dim 3, not Dim 8. A stale
GPU-size doc comment is Dim 3; a stale GPU-size code literal is Dim 7. NIFAL/material translation correctness is out of
scope (/audit-nifal) — this audit owns only the debt around that tier.
Phase 3: Merge
- Read all
/tmp/audit/tech-debt/dim_*.md. - Combine into
docs/audits/AUDIT_TECH_DEBT_<TODAY>.md: Executive Summary (findings by severity + delta vsbaseline.txt), Baseline Snapshot (the Phase-1 counts), Top 10 Quick Wins (trivial/small effort),
Top 5 Medium Investments (splits, consolidations), Findings (HIGH → MEDIUM → LOW, then by dimension),
Deferred (gated on an in-progress milestone; name it). - Remove cross-dimension duplicates per the rules above.
Phase 4: Cleanup
rm -rf /tmp/audit/tech-debt; tell the user the report is ready; suggest/audit-publish docs/audits/AUDIT_TECH_DEBT_<TODAY>.md.
GitHub Labels
Findings publish under tech-debt (plus the standard <severity> and <domain> labels; /audit-publish applies it forTECH_DEBT reports). Two sibling kind labels split the bucket — apply the one that matches:
doc-rot— documentation drifted from code (stale ROADMAP row, a SKILL naming a deleted symbol, a comment describing
removed behaviour); publishes asdocumentation, notbug.test-gap— missing, vacuous or non-asserting coverage (an#[ignore]d test with no data gate, an entry point with
zero tests).
Pure debt (dead code, duplication, magic numbers, oversized files, stale markers) staystech-debt+bug.