> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Dead Code Detection

> Unified pipeline at scripts/deadcode/ wrapping Fallow with detectors for routes, Edge Functions, feature flags, and i18n.

A unified pipeline at `scripts/deadcode/` that wraps Fallow and adds detectors for routes, Edge Functions, feature flags, and i18n. Replaces the bespoke `audit-unused-*` scripts.

## Commands

| Command                                    | Use                                                                                                                                                                                                                                                                                     |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `npm run deadcode`                         | Full run. Writes `reports/active/deadcode-{date}.{json,md}`.                                                                                                                                                                                                                            |
| `npm run deadcode:ci`                      | Regression check against `.deadcode-baseline.json`. Exits non-zero on regression.                                                                                                                                                                                                       |
| `npm run deadcode:triage -- --core <core>` | Per-core triage worksheet (`reports/triage/<core>-triage.{md,json}`) proposing a disposition per item.                                                                                                                                                                                  |
| `npm run deadcode:pageless`                | Writes `docs/development/PAGELESS_FEATURE_BACKLOG.md` — non-barrel components/hooks for launch-ready specs that are unwired (finished features lacking a host page; product-prioritized).                                                                                               |
| `npm run deadcode:core-report`             | Writes `docs/development/CORE_CLEANUP_PRIORITIZATION.md` — per-core buckets (delete-superseded / delete-orphan / wire-genuine / page-less / defer-keep) of unwired-file items, sorted by actionable count = recommended execution order. Measure-first prioritization across all cores. |

## What it detects

| Detector         | Surface                                   | Source                                                                                                                                                                                                                 |
| ---------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fallow`         | files, exports, deps, cycles, dup exports | wraps `fallow dead-code --production --format json`                                                                                                                                                                    |
| `routes`         | `<Route path>` declarations               | scans `src/routes/**/*.tsx` for declarations and matches references by exact path, parametric template, **or path-segment run** (so relative child routes like `path="dashboard"` are matched against `/pm/dashboard`) |
| `edge-functions` | Supabase Edge Functions                   | scans `supabase/`, `src`, `.github`, `scripts` for `functions.invoke('<name>')`, `functions/v1/<name>` URLs, `createCronHandler('<name>')` cron registration, and `[functions.<name>]` blocks in `config.toml`         |
| `flags`          | PF-45 `useFeatureFlag('key')`             | greps call sites; cross-references registry JSON snapshot                                                                                                                                                              |
| `i18n`           | i18n keys                                 | stub — repo has no i18n library; will activate when one is adopted                                                                                                                                                     |

## Classification

Every issue is labeled `auto-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](#specode-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)

**Barrel reclassification:** a re-export `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:

| Signal         | Frontmatter values                                                                                                   |
| -------------- | -------------------------------------------------------------------------------------------------------------------- |
| `LAUNCH_READY` | `complete`, `ready`, `implemented`, `shipped`                                                                        |
| `PROTECTING`   | `specification`, `draft`, `in_progress`, `tasks_generated`, and all other active lifecycle values — the safe default |
| `NONE`         | `archived`, `deferred`, `superseded`, or no lifecycle field present                                                  |

`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.:

```yaml theme={null}
affected_files:
  - src/cores/hr/components/handbook/**
  - src/cores/hr/hooks/handbook/**
```

Globs are matched with [minimatch](https://github.com/isaacs/minimatch) by `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

```bash theme={null}
# 1. Generate proposals (worksheet written to reports/affected-proposals/<core>.md)
npm run specs:propose-affected -- --core <core>

# 2. Review the worksheet, then write high-confidence globs into spec frontmatter
npm run specs:apply-affected -- --core <core>
```

High-confidence matches are applied automatically; lower-confidence suggestions remain in the worksheet for manual review.

## Allowlist

Add entries to `.deadcode-allowlist.json` to protect a file from auto-drop:

```json theme={null}
[
  {
    "path": "src/example/foo.ts",
    "reason": "called by external Zapier webhook",
    "spec_ref": "PF-EXTERNAL-INTEGRATIONS",
    "added": "2026-05-23"
  }
]
```

`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 the `pf_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

1. Create `scripts/deadcode/detectors/<name>.ts` exporting a `Detector` (matches `{ name, run(ctx) }`).
2. Add it to the `detectors:` array in `scripts/deadcode/run.ts`.
3. Write unit tests at `tests/unit/deadcode/detectors/<name>.test.ts`.
4. Update this doc.

## Migrating from the old scripts

The retired scripts and their replacements:

| Old                                 | New                                                                              |
| ----------------------------------- | -------------------------------------------------------------------------------- |
| `audit-unused-files.ts`             | `deadcode` (Fallow + classifier; classified output replaces the bespoke buckets) |
| `audit-unused-and-consolidation.ts` | `deadcode` annotations (`annotations.consolidationCandidate`)                    |
| `audit-barrel-files.ts`             | `deadcode` annotations (`annotations.barrel`)                                    |
