ADR 0014: Dead Code Analysis and Repository Hygiene

Ratification

Adopted before ADR 0018. There was no separate ratification process. Git history for this file on main is the record.

Context

Why this matters: Dead code is not harmless—it confuses readers, hides the real execution path, and makes refactors riskier. Unused imports are easy wins: the linter catches them cheaply. Whole unused functions are harder: static “dead code” detectors use heuristics and can false-positive on dynamic registration or tests-only symbols.

We combine a strict gate (Ruff on every PR) with a softer periodic scan (Vulture) so routine work stays fast while deeper cleanup still happens on a schedule.

Decision

Adopt a two-layer approach:

  1. Ruff (required on every PR): keep the existing E/F rules so F401 (unused imports) is enforced in make lint-check / CI. Extend with RUF100 to remove obsolete noqa directives that no longer match an enabled rule.
  2. Vulture (advisory): configure [tool.vulture] in pyproject.toml for paths app, tests, and scripts. Run locally via make dead-code-check. Do not add Vulture to the default PR quality gate; run it on a weekly schedule (and manual dispatch) in GitHub Actions so maintainers triage findings without blocking every change.

Removals of allegedly dead code require human confirmation and tests (or equivalent evidence) before merge; static analysis alone is not sufficient for deletion.

Scope

Alternatives considered

  1. Vulture in CI for every PR.
    • Pros: fastest feedback.
    • Cons: false positives create churn; tuning whitelists becomes a constant tax.
  2. Ruff-only (no Vulture).
    • Pros: zero extra dependency, very stable signal for imports.
    • Cons: misses unused functions/classes that imports still reference indirectly.

Consequences

Positive

Trade-offs

Implementation notes

Page history

Date Change Author
Added Page history section (repository baseline). Ivan Boyarkin