Find Dead Code

Dead code is more than clutter. It misleads humans and AI alike - false grep matches, confusing imports, wasted context tokens. Every unreachable function is a distraction that makes your codebase harder to reason about. Pharaoh traces reachability from production entry points to find what's truly unreachable.

The workflow

1. Find unreachable functions

Ask your AI tool:

Find dead code in the utils module.

This triggers get_unused_code. Functions come back in two tiers:

  • Dead - no callers in the graph AND no text references anywhere in the codebase. Safe to delete.

  • Likely Dead - no callers in the graph BUT mentioned as a string somewhere. Could be dynamically dispatched via string lookup, or could just be referenced in a comment.

2. Find duplicate logic

Ask your AI tool:

Find duplicate logic across the codebase.

This triggers get_consolidation_opportunities. You get back:

  • Identical body hashes - two functions with the same implementation in different modules

  • Signature twins - functions with identical signatures that likely do the same thing

  • Parallel consumers - multiple modules reading the same DB table or API endpoint

  • Competing DB access - different modules writing to the same table without coordination

3. Verify specific functions

Ask your AI tool:

This triggers check_reachability (Pro). It gives a definitive answer: the function is either connected to a production entry point or it isn't.

What to look for

  • Dead tier - high confidence. These functions have no callers and no text references. Delete them. If something breaks, it means a dynamic dispatch pattern wasn't captured - but this is rare for the Dead tier.

  • Likely Dead tier - investigate the text references before deleting. If the reference is a comment, a documentation string, or a log message, the function is still dead. If the reference is a string used in a dispatch table or plugin registry, the function is alive.

  • Signature twins - two functions with identical parameter types and return types in different modules usually mean someone copied instead of importing. Consolidate them into one shared function.

  • Parallel consumers - multiple modules independently reading the same DB table often means duplicated query logic. One module should own the data access, and the others should call it.

Tips

  • Start with a single module, not the whole codebase. A focused cleanup is easier to verify, easier to review, and less likely to cause unintended breakage. Chain the tools: get_unused_code to find candidates, check_reachability to verify, then delete with confidence.

  • Dead code compounds. A function becomes dead, then the functions that only existed to support it become dead too. A quarterly cleanup pass prevents dead code from becoming archaeological layers that nobody dares touch.

Last updated