Our review
Audits a Rust codebase for technical debt like dead code, magic numbers, duplicate logic, stale documentation, and oversized files, focusing on nine dimensions with configurable depth.
Strengths
- Covers multiple dimensions of tech debt (9 dimensions) systematically.
- Provides concrete recipes to discover current instances, not static lists.
- Includes severity promotion rules to prioritize critical issues.
- Generates a baseline snapshot for tracking debt over time.
Limitations
- Only works for Rust codebases with the specific structure (crates/).
- Requires prior setup of .claude/commands and audit infrastructure.
- Deep mode can be time-consuming for large codebases.
- May not catch all forms of tech debt (e.g., design debt).
Use this skill when you need a systematic, repeatable technical debt audit before a major refactoring or release.
Do not use this skill for identifying correctness bugs or for a one-time quick code review without ongoing maintenance.
Security analysis
SafeThe skill uses only read-only file inspection and GitHub issue listing commands (find, grep, gh) to gather technical debt metrics, with no destructive or data-exfiltration instructions. All file output is to /tmp.
No concerns found
Examples
Run a tech debt audit with depth=shallow and focus on dimensions 1,3,5 (stale markers, dead code, magic numbers).Perform a comprehensive tech debt audit across all dimensions with depth=deep.Audit technical debt specifically for stale documentation (dimension 7) with shallow depth.description: "Audit accumulated technical debt — stale markers, dead code, duplication, magic numbers, stub impls, doc rot, oversized files" argument-hint: "--focus <dimensions> --depth shallow|deep"
Tech-Debt Audit
Audit ByroRedux for accumulated technical debt: code that compiles, passes tests, and ships, but quietly raises the cost of every future change. The goal is not correctness bugs (other audits own that) — it is decay that crept in since the last cleanup pass.
Every dimension below is a DISCOVERY RECIPE, not a finding list. Instances churn between audits (markers get deleted, files get split, line numbers drift). So each dimension hands you a command to enumerate current instances, then a triage rule. Do not trust any hardcoded instance list — there are none here on purpose. Re-run the recipe; report what it surfaces today.
Architecture: Orchestrator. Each dimension runs as a Task agent (max 3 concurrent).
See .claude/commands/_audit-common.md for project layout, the 21-crate roster,
methodology, deduplication, context rules, severity, and finding format. Do not
duplicate any of that here. The newest crates — crates/pex/ (M47.2 compiled-
Papyrus .pex decompiler), crates/save/ (M45 full-ECS snapshot save/load), and
the expanded crates/scripting/ (M47.1/M47.2 recognizer chain) — are young code
that has not yet seen a debt sweep; the dimensions below should reach them.
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. Default:deep.
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>-NNN(e.g.TD7-050= Dim 7 Doc Rot, finding 50). The path-validation gate (_audit-validate.sh, #1114) was itself aTD7-*finding — recurring stale-path findings are what motivated the gate.
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
$ARGUMENTSfor--focus,--depth. 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). - Snapshot totals so the next audit can diff:
Orientation only (will drift — re-run, never quote): the marker total runs ~20,{ echo "TODO/FIXME/HACK/XXX: $(grep -RInE '(TODO|FIXME|HACK|XXX)\b' crates byroredux | wc -l)" echo "allow(dead_code): $(grep -RInE 'allow\(dead_code\)' crates byroredux | wc -l)" echo "unimplemented!/todo!(): $(grep -RInE 'unimplemented!|todo!\(\)' crates byroredux | wc -l)" echo "#[ignore] tests: $(grep -RIn '#\[ignore\]' . | wc -l)" echo "files >2000 LOC: $(find crates byroredux -name '*.rs' -exec wc -l {} + | awk '$1>2000 && $2!="total"' | wc -l)" } > /tmp/audit/tech-debt/baseline.txtunimplemented!/todo!()is currently 0 (the engine prefers explicit fallbacks over panics — a freshtodo!()is therefore notable),#[ignore]runs in the low-hundreds (mostly Vulkan/smoke gating, not debt), and the2000-LOC set is ~7 files (Dim 1).
Phase 2: Dimension Agents
Ordered by debt impact: complexity and duplication compound across every future
edit; doc/audit rot misdirects the next audit; markers and dead code are
cheap. Each agent writes /tmp/audit/tech-debt/dim_<N>.md.
Dimension 1: File / Function / Module Complexity
The highest-leverage debt: an oversized file taxes every edit, review, and merge.
Discovery:
find crates byroredux -name '*.rs' -exec wc -l {} + | awk '$1>2000 && $2!="total"' | sort -rn
Session 34/35/36 (2026-05) split the original oversized set (acceleration.rs,
dispatch_tests.rs, cell/tests.rs, draw.rs, scene_buffer.rs, context/mod.rs,
import/mesh.rs, blocks/collision.rs, nif/anim.rs) into submodules — all of
those are closed; do not re-file them. Membership has since turned over: the
two big Vulkan-context files grew after re-split, and several byroredux/
files crossed 2000. Re-run the command; the threshold is 2000 LOC (the
Session-34 split target). Whatever it lists today is the live set — including any
file the skill once cited as a success (a previously-split module can grow back
over threshold).
Per oversized file, propose a split AXIS by responsibility (not by line count):
- A Vulkan
context/file → per-pass recording groups (geometry / RT / denoise / composite / overlay) or struct+new() vs Drop vs accessors. Vulkan-recording splits are render-pass-adjacent — seefeedback_speculative_vulkan_fixes.mdbefore proposing barrier/order changes. byroredux/src/asset_provider/→ BSA/BA2 resolution vs TextureProvider vs mesh extraction.byroredux/src/main.rs→ App/ApplicationHandler event loop vs system registration vs boot/config.byroredux/src/commands/→ console-command groups, already split per-domain (world_info / assets / view / scene / shared) under #1323; check the submodules stay cohesive, not re-bloated.crates/nif/src/blocks/particle.rs→ typed emitter/ctlr structs vs the opaqueNiPSysBlockfallback vs grow/fade modifiers.crates/nif/src/import/collision/mod.rs→ split per bhk shape family (primitive/compound/mesh/compressed), mirroringcrates/nif/src/blocks/collision/.crates/core/src/ecs/resources/mod.rs→ partially split already (SkinSlotPoolextracted toskin_slot_pool.rsunder #1869;mod.rsnow 1210 LOC, under threshold). Split further per resource domain (rendering/world/audio/scripting) only if it re-bloats.crates/plugin/src/esm/records/actor.rs→ split per NPC_ data-group (13 groups).
Also flag: functions >200 LOC (propose extraction); match arms >50 cases
(want a lookup table); nesting depth >5 (state-machine extraction); a mod.rs /
lib.rs with >20 pub use (doing two jobs). cargo +nightly clippy --all-targets -- -W clippy::cognitive_complexity if available, else inspect the worst offenders.
Dimension 2: Logic Duplication
CLAUDE.md global policy is explicit: improve existing code, never duplicate logic. Every finding must name a concrete consolidation site.
Discovery: target subsystems with N>1 sibling files, then read for repeated scaffolding:
ls crates/nif/src/blocks/*.rs crates/plugin/src/esm/records/**/*.rs crates/renderer/src/vulkan/*.rs byroredux/src/cell_loader/*.rs
Look for:
- Block-parser scaffolding repeated across
crates/nif/src/blocks/(header read → field read → fixup) that should funnel through a shared helper/macro. - Texture-upload chains (BC1/BC3/BC5/RGBA) duplicated in
crates/renderer/src/vulkan/. - The same image-layout barrier sequence repeated per render pass.
vk::WriteDescriptorSetbuilder boilerplate.- ESM sub-record parse loops repeated across
crates/plugin/src/esm/records/. - Z-up → Y-up coordinate flips reimplemented outside the canonical homes
(
crates/nif/src/import/coord.rs,crates/nif/src/anim/coord.rs) — any other call site is a leak.
Dimension 3: Stale Documentation & Comments
Doc rot is high-impact debt because it misleads the next reader and the next audit. Run the path gate first (it is also Dim 9's input):
.claude/commands/_audit-validate.sh
Any STALE refs it prints are auto-eligible findings (effort: trivial). Then sweep for content rot the gate cannot see:
- Numeric claims in doc comments that drift from a pinned test. The canonical
trap:
GpuCamera/GpuInstance/GpuMaterialbyte sizes andVertex::SIZE. Do NOT trust prose — cross-check against the layout test, whose value is authoritative and whose name may itself be stale:grep -rn "fn gpu_camera_is\|fn gpu_instance_is\|assert_eq.*size_of" crates/renderer/src/vulkan/scene_buffer/gpu_instance_layout_tests.rs - Doc comments naming renamed/deleted symbols. The recurring one: the deleted
render-time
Material::classify_pbr(PBR resolution moved to the parse-time NIFAL boundary). Several doc-comments incrates/core/src/ecs/components/material.rsstill name it — each must frame it as deleted/historical, never as a live entry point. Enumerate and read each:The surviving symbols are the free functiongrep -n "classify_pbr" crates/core/src/ecs/components/material.rsclassify_pbr_keywordand the methodMaterial::resolve_pbr;metalness/roughnessare plain resolvedf32. (This overlaps Dim 8 — report material doc rot under Dim 3.) - ROADMAP.md milestones marked "in progress" whose issues are all closed (or vice versa) — cross-check
git log/gh issue. docs/feature-matrix.md— re-check each milestone row against shipped code (git log --grep M45,--grep M47.2, …). The known M45/M47.2 lag was fixed on 2026-06-21 (the Save/load row was removed, the M47.2 row now reads "✓.pexrecognizer slice … full transpiler deferred"), so those are clean — but the matrix is a status floor, not a record of what exists, so any future milestone can drift the same way. Flag any row whose status contradicts the crate that implements it.- HISTORY.md entries referencing later-reverted work.
- README.md command examples whose flags/paths changed.
docs/legacy/references to Gamebryo source paths that moved.crates/renderer/shaders/triangle.fragdoc comments quoting outdated GPU struct byte sizes — cross-check the layout test, not the prose.
Path convention (post-#1114): a backticked .ext path in any audit-*.md or
this file asserts "exists right now". Forward-looking (not-yet-created) or
backwards-looking (deleted) refs must NOT use backticks. The gate fails on any
backticked path that does not resolve. The gate now globs both the shared
.claude/commands/_audit-*.md files AND every .claude/commands/audit-*/SKILL.md
subdir (so paths in this very file ARE gate-covered) — run it before committing.
Dimension 4: Audit-Finding Rot
The audit infrastructure decays like any other code, and stale baselines actively misdirect future audits. Discovery:
.claude/commands/_audit-validate.sh # structural path gate (#1114)
ls .claude/commands/audit-*.md docs/audits/
- STALE refs from the gate that live in other audit skills → Dim 4 findings (trivial).
- Symbol-anchor refs the gate cannot verify (e.g.
crates/audio/src/lib.rs::drain_pending_oneshots) — spot-check the symbol still exists. - "Existing: #NNN" callouts in skills where the issue is now CLOSED — reframe as a closed-state baseline.
- Skill files quoting a dimension count ("all N dimensions") that no longer matches the live list.
docs/audits/reports >90 days old whose CRITICAL/HIGH findings are not all triaged on GitHub.- Do NOT flag
.claude/issues/<N>/ISSUE.md"Status: Open" drift — dropped per TD10-001 / #1156: local issue files are immutable snapshots; GitHub is authoritative. Querygh issue view <N> --json statefor live state.
Dimension 5: Stale Markers (TODO / FIXME / HACK / XXX)
Discovery:
grep -RInE '(TODO|FIXME|HACK|XXX)\b' crates byroredux
grep -RInE '(TODO|HACK)' crates/renderer/shaders/
Triage each (skip markers <30 days old unless they name a closed issue):
git blamefor age — anything >6 months gets reported.- Does it name an issue number? Is that issue still open? Closed issue + live marker → "marker outlived its driver" (delete or reopen).
- Does it name a milestone (M21, M29, …) now complete per ROADMAP.md?
// TODO: implementon a path now reachable from a shipped CLI flag → promote (see severity table).- False positives to exclude:
XXXXis the ESM extended-size sub-record tag (crates/plugin/src/esm/reader.rs,records/misc/magic.rs) — protocol, not a marker.// FIXME notereferencing a reference implementation's FIXME (e.g.crates/bgsm/src/bgem.rs) is documentation of upstream, not our debt. - Must-not-delete: the third-party attribution block atop
crates/renderer/shaders/triangle.frag(GLSL-PathTracer MIT notice + Burley 2012 citation, ~first 30 lines). Flag any edit that strips/truncates it — MIT requires the notice travel with the code.
Dimension 6: Stub & Placeholder Implementations
Discovery:
grep -RInE 'unimplemented!|todo!\(\)|panic!\("not ' crates byroredux
grep -RInE '// *(stub|TODO: real|placeholder|not yet)' crates byroredux
The first command currently returns nothing — the codebase prefers explicit fallbacks to panics, so any hit is genuinely notable. For each:
- Reachable from a shipped CLI flag or smoke test? → promote to MEDIUM.
- Functions returning
None/Vec::new()/Default::default()with a "// stub"/"// TODO: real impl" comment. - Trait impls with empty bodies that the trait docs say should do work.
- Per-game ESM record coverage in
crates/plugin/src/esm/records/— fully wired vs stubbed per game; cross-check ROADMAP.md per-game compat matrix. (The legacy per-game stubs incrates/plugin/src/legacy/were removed under #390 — coverage now lives in the unified records tree; do not re-file the removed stubs.) - Console commands in
byroredux/src/commands/that exist but no-op / print "TODO".
Dimension 7: Magic Numbers & Hardcoded Constants
Discovery: read the version-gate and budget sites; do not regex blindly (most literals are legitimate).
- Bare numeric literals in
crates/nif/src/blocks/compared against version codes → should be aNifVersionconstant. - Vulkan
MAX_*/MIN_*hardcoded inline → referencevk::PhysicalDeviceLimitsor a named constant. - Shader
#defineprovenance: every shader define is generated from one Rust source —crates/renderer/src/shader_constants_data.rsisinclude!d by bothcrates/renderer/src/shader_constants.rsandcrates/renderer/build.rs(which emitsshaders/include/shader_constants.glsl). The generated-header infra exists; the check is "every shader#defineis sourced fromshader_constants_data.rs; flag any literal that bypasses it" (lockstep risk HIGH —feedback_shader_struct_sync.md). - GPU
#[repr(C)]size literals:GpuCamera,GpuInstance,GpuMaterialsizes are pinned bygpu_instance_layout_tests.rs. Flag any inline size literal that should reference those tests, and any doc comment quoting an outdated size (overlaps Dim 3). Get the live values from the test, not from memory:grep -rn "fn gpu_camera_is\|fn gpu_instance_is\|size_of::<Gpu" crates/renderer/src/vulkan/scene_buffer/gpu_instance_layout_tests.rs - Frame/ray/cache budgets (
GLASS_RAY_BUDGET,MAX_TOTAL_BONES,MAX_MATERIALS, …) scattered vs in one tunable module. - ESM sub-record sizes hardcoded (
if data.len() == 24) → named constant from 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
Discovery:
grep -RInE 'allow\(dead_code\)' crates byroredux
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"
- Each
#[allow(dead_code)]— actually called now, or still dead? Delete if dead. pub fnin a private module no one imports (cargo +nightly rustc -- -W unused).mod.rs/lib.rsre-exports with no downstream consumer._-prefixed params that survived a refactor (CLAUDE.md: delete, don't rename to_var).// removed: …breadcrumbs (CLAUDE.md: delete completely, no breadcrumbs).- Re-exports of deleted types kept "for compatibility" — ByroRedux has no external consumers yet, so these are pure rot.
Cargo.tomlfeature flags with only one branch (always-on/always-off) → remove the flag.#[deprecated]items with no consumers → delete, don't deprecate.- Do NOT flag:
cfg(test)/cfg(debug_assertions)-gated code, FFI boundary functions, or public API of a workspace-internal crate a future binary will consume (note such cases rather than deleting).
Dimension 9: Test Hygiene
Discovery:
grep -RIn '#\[ignore\]' . | grep -v target/
Most #[ignore]s gate Vulkan/smoke tests that need a GPU or on-disk game data —
those are not debt. Triage the rest:
- Each
#[ignore]test: referenced issue still open? If it guards a closed CRITICAL/HIGH fix → MEDIUM (severity table). - Tests with only smoke assertions (
assert!(result.is_ok())and nothing else) — should assert on values. - Commented-out assertions inside otherwise-passing tests (
// assert_eq!(…)). #[cfg(feature = "…")]-gated tests where the feature is never enabled in CI.- Tests that
println!without a follow-up assert. byroredux/tests/golden_frames.rs(opts into--ignored) — still runnable, golden image current.- Cross-reference "must not regress" lines in other audit skills (e.g.
audit-performance) — each named regression test still present and not#[ignore]d.
Cross-Dimension Dedup
A TODO inside a dead function reports under Dim 8 (Dead Code), not also Dim 5.
Material doc rot reports under Dim 3, not also Dim 8. A stale GPU-size doc comment
reports under Dim 3; a stale GPU-size code literal under Dim 7. NIFAL/material
translation correctness is out of scope here — that is /audit-nifal. This
audit only owns the debt around that tier (dead code, stale doc, leftover
breadcrumbs).
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 vs
baseline.txt. - Baseline Snapshot — the Phase-1 counts, so the next audit can diff.
- Top 10 Quick Wins — trivial/small effort, immediate readability or compile-time payoff.
- Top 5 Medium Investments — file/function splits, duplication consolidations.
- Findings — by severity (HIGH → MEDIUM → LOW), then by dimension.
- Deferred — findings gated on an in-progress milestone; name the gating milestone.
- Executive Summary — findings by severity + delta vs
- 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 Label
Findings publish under the tech-debt label (plus the standard <severity> and
<domain> labels). It is registered in the repo — /audit-publish applies it
automatically when a finding's audit type is TECH_DEBT.
Next.js App Router Expert
Development
A skill that turns Claude into a Next.js App Router expert.
README Generator
Development
Creates professional and comprehensive README.md files for your projects.
API Documentation Writer
Development
Generates comprehensive API documentation in OpenAPI/Swagger format.