Dead Code Expert
Find and eliminate dead code, duplicate implementations, parallel split-brain logic across architectural boundaries, dead deployment artifacts (env vars, configs, manifests, schemas, routes, assets), and unnecessary complexity across any programming language and stack. Every finding explains WHY the code is dead and the concrete cost of keeping it (cognitive overhead, build time, misleading developers, masking bugs, drift bugs).
How to Think About Dead Code
Before flagging anything, identify which category it belongs to:
- Layer 1 -- Certainly Dead: Unreachable code after return/break/throw, unused private functions, unused local variables, imports with zero references. Safe to remove immediately.
- Layer 2 -- Probably Dead: Exported functions with no callers in the project, commented-out code blocks,
#[allow(dead_code)]/// eslint-disable unusedsuppressions, permanently-off feature flags. Verify before removing. - Layer 3 -- Suspiciously Alive: Code that LOOKS dead but may be used via reflection, serialization, framework magic, dynamic dispatch, DI container resolution, or public API surface. Investigate before touching.
- Layer 4 -- Hidden by Spaghetti: Dead code locked inside large structural smells (god classes, cyclic imports, divergent change). The structural smell makes the dead code invisible. Surface the smell first, then the dead code inside. → Consult false-positives reference for the full 11-category checklist and scoring framework. → Consult structural smells reference when dead code is hidden inside spaghetti.
When dead code is found, reframe it as a design question:
| Dead Code Pattern | Don't Just Say | Ask Instead |
|---|---|---|
| Unused function | "Delete it" | Why was it written? Is there a missing caller? |
| Duplicate implementation | "Remove one" | Which is canonical? Why did duplication happen? |
| Commented-out block | "Delete it" | Is there in-progress work? Check git blame. |
| Unused abstraction layer | "Inline it" | Was it speculative generality? |
| Dead feature flag | "Remove the branch" | Is there a deprecation process to follow? |
| Same logic in client and server | "Pick one" | Where's the canonical source of truth? Should this be codegen? |
| Stale manifest entry / env var | "Delete it" | Is this read by a runtime convention or framework? |
Detection Process
When scanning for dead code, work through these categories in order.
-
Unused Imports -- Imports/includes/requires with no reference in file. → Consult grep patterns for per-language detection.
-
Unused Variables & Parameters -- Assigned but never read (dead stores).
-
Unused Functions & Methods -- Defined but never called.
-
Unused Classes & Types -- Defined but never instantiated or referenced. → Consult detection catalog for categories 2-6 with per-language tools.
-
Unreachable Code -- Code after return/break/throw, dead branches (always-true/false conditions).
-
Commented-Out Code -- Code blocks in comments (not documentation).
-
Duplicate / Dual Implementations -- Same logic implemented twice differently. Includes cross-boundary "split-brain" duplication (client↔server validation, DTO↔entity↔frontend type triplets, two services solving the same problem, duplicate enums across languages).
-
Speculative Generality -- Abstractions used in exactly one place, interfaces with single implementation, unused parameters kept "for future use". → Consult duplicate code reference for clone types, dual implementation patterns, cross-boundary split-brain catalog, and DRY escalation.
-
Dead Test Code -- Skipped tests, unused fixtures, orphaned test files.
-
Debug Artifacts --
console.log,print(),dbg!(),TODO/FIXMEmarkers left in production code. -
Dead Assets, Configuration, & Infrastructure -- Unused environment variables, config keys nothing reads, asset files / localization keys / images nothing references, Dockerfile stages whose output is discarded, Kubernetes resources nothing routes to, Terraform variables/modules with no consumer, CI/CD steps producing artifacts nothing uses, database tables/columns nothing queries, HTTP routes with no caller, frontend routes with no
<Link>, scripts inscripts/no pipeline invokes. → Consult deployment dead code reference for per-artifact-type detection.
Stack-Specific Patterns
Source-symbol detection misses framework- and build-system-level dead code: DI registrations with no consumers, IBOutlets bound to deleted views, API routes with no client, Helm values nothing templates, dead Tailwind utilities, unawaited coroutines, EF Core navigations never traversed. → Consult stack-specific patterns for SwiftUI/iOS, Rust, TypeScript/React/Next.js, C#/.NET, Python, and C/C++ detection beyond standard linters.
Thinking Prompts
Before removing code, work through:
- Is this genuinely dead? Check for reflection, serialization, dynamic imports, framework conventions, DI container resolution, public API consumers. → Consult false-positives reference before every medium-confidence removal.
- Why does this exist? Check
git log/git blame. If someone wrote it recently, it might be in-progress work. If it's years old with no references, it's dead. - What's the cost of keeping it? Cognitive overhead for every developer who reads it. Misleading grep results. False confidence from tests that exercise dead paths. Build time for code nobody uses. For split-brain duplication: the cost is silent drift bugs in production.
- Is this hidden by a bigger smell? A god class with 30 unused methods isn't 30 separate findings — it's one structural smell. Name the smell, then list the dead code inside.
Confidence Levels
Label every finding:
- certain -- Compiler/linter confirms it (unused import, unreachable after return). Remove immediately.
- high -- No references found in project-wide search. Remove after quick verification.
- medium -- Might be used via dynamic means (reflection, templates, DI container, string-based lookup). Investigate first.
- low -- Potentially used by external consumers (library public API, plugin interface, external API caller). Do not remove without understanding consumers.
Output Format
Group findings by file (or by artifact for deployment-level findings). For each finding:
- File path and line number (or artifact path)
- Confidence level
- Category (from the 11 categories above)
- What is dead -- name the specific symbol, block, artifact, or pattern
- Why it's dead -- the evidence (zero references, unreachable, no consumer, etc.)
- Cost of keeping it -- cognitive overhead, misleading results, build time, masking bugs, drift risk
- Recommended action (delete, inline, consolidate, investigate, generate-from-source)
End with a prioritized summary: certain items first, then high confidence, then medium. For split-brain findings, recommend a canonical source and a codegen / shared-package strategy.
The AI Slop Test
If a codebase uses AI coding tools, check for AI-specific dead code fingerprints: copy-pasted logic across services, wrapper functions adding nothing, single-impl interfaces, commented-out "previous attempts", exc