scripts/deadcode/ that wraps Fallow and adds detectors for routes, Edge Functions, feature flags, and i18n. Replaces the bespoke audit-unused-* scripts.
Commands
What it detects
Classification
Every issue is labeledauto-drop | review | keep per the spec at docs/superpowers/specs/2026-05-23-dead-code-cleanup-design.md.
Auto-drop requires:
- No spec with a LAUNCH_READY or PROTECTING signal (see Spec↔code linkage below) governs the file/symbol
- Detector marks the surface dead
- Age ≥ 6 months (or 3 months for flags). Age is computed from the most recent commit that is neither format-only nor a bulk reconcile/merge/sync commit, so a repo-wide reconcile does not reset every file’s age to ~0.
- Not in a regulated core (CL/PM/HR/RH/GR/FA)
- Not in
.deadcode-allowlist.json - Not structurally-protected (auto-generated files, migrations, spec templates)
index.ts flagged unused-file is reclassified to keep (barrel re-exports live modules — not actionable) when it fronts ≥1 live module — i.e. a re-export target that is not itself in the run’s unused-file set (consumers just import the sub-modules by direct path, not the barrel). A barrel whose every target is also unused stays flagged (it’s a genuinely-dead cluster). See scripts/deadcode/barrel.ts.
Everything else falls to review (human triage) or keep (protected).
Page-less features: finished components/hooks for LAUNCH_READY specs that the report shows unwired can’t be wired mechanically (no host page exists) — they’re collected into docs/development/PAGELESS_FEATURE_BACKLOG.md via npm run deadcode:pageless as product-prioritized feature work, not deadcode noise.
Spec↔code linkage
The triage engine (scripts/deadcode/triage.ts) uses a spec signal to determine whether a file is protected by a governing specification. The signal is derived from whichever frontmatter key is present — status: or pipeline_status: — mapped as follows:
LAUNCH_READY items produce WIRE_DIRECT triage; PROTECTING (or PHI-flagged) items produce WIRE_FLAG; NONE allows DELETE/DEFER.
affected_files — declaring code ownership
A spec declares the code it governs via the affected_files frontmatter array of path globs, e.g.:
governingSpecsForPath(idx, path) in scripts/deadcode/spec-index.ts. Any file matched by a spec with a LAUNCH_READY or PROTECTING signal is protected from auto-drop.
Extending coverage for a core
Allowlist
Add entries to.deadcode-allowlist.json to protect a file from auto-drop:
path can be exact or a glob. reason and spec_ref are required.
Feature-flag registry snapshot
The flags detector cross-references in-repo call sites against thepf_feature_flags table. In v1, supply a JSON snapshot at .deadcode-cache/feature-flags-registry.json (array of flag-key strings). A future task will automate the snapshot via a CI step or admin tool export.
CI behavior
.github/workflows/deadcode.yml runs deadcode:ci on every PR to development / main, fails on regression vs the baseline total, uploads the full report as an artifact, and posts an excerpt as a PR comment.
Regression baseline (.deadcode-baseline.json)
deadcode:ci fails when the orchestrator’s total issue count exceeds totalIssues in .deadcode-baseline.json. This is the orchestrator’s own gate, distinct from Fallow’s .fallow-baseline.json (which gates the fallow tool itself). Refresh .deadcode-baseline.json — and re-run npm run deadcode — only when intentionally accepting new findings.
Cache
The orchestrator caches under.deadcode-cache/ (gitignored). Invalidated automatically when input files change. Delete the directory to force a full rebuild.
Adding a new detector
- Create
scripts/deadcode/detectors/<name>.tsexporting aDetector(matches{ name, run(ctx) }). - Add it to the
detectors:array inscripts/deadcode/run.ts. - Write unit tests at
tests/unit/deadcode/detectors/<name>.test.ts. - Update this doc.