-
Notifications
You must be signed in to change notification settings - Fork 908
Night Watch Dead Code
Assigned to: Cindy's Navi (cixzhang)
Goal: Keep the codebase free of dead code by detecting unused files, exports, types, and devDependencies and removing the high-confidence ones via PR.
Tooling: knip, run from outside the repo. knip only reads a checkout to resolve the module graph, so the binary, its config (knip.jsonc), and the runner live in the Night Watch operator's workspace, not in facebook/astryx. Nothing is added to the public repo's package.json or lockfile. knip reads each package's exports/bin as entry points, so published API surfaces are never reported as unused.
The canonical tooling lives in the operator's workspace at memory/xds-night-watch/deadcode-tools/:
-
knip.jsonc: the public-API-safe config (entry patterns + ignores) -
check-deadcode.mjs: the runner (invokes knip with--directory <checkout> --config knip.jsonc, handles the small-host memory workaround) -
package.json: pinsknip -
bootstrap.sh: re-materializes the tools dir on the (ephemeral) xds node and installs knip
Because the xds node is wiped on sandbox reset, each run first bootstraps the tools dir from the workspace copies, then runs the detector against a checkout that has node_modules installed.
Once per night, producing one PR per run (max). Hourly cron with the standard business-hours guard (skip 9am-5pm PST on weekdays); a state gate limits it to one real run per day.
Dead code accumulates silently. A helper no one calls after a refactor, a type left behind, a devDependency for a removed workflow. None of it breaks tests or CI, so nothing catches it. This role runs a real, reproducible tool and turns its high-confidence findings into small, safe removals.
Detect and, for high-confidence categories, remove:
-
Unused files in
packages/*(source files imported by nothing, not reachable from any entry point) -
Unused exports in
packages/*(an exported symbol no other module imports) -
Unused exported types in
packages/* -
Unused
devDependencies(a dev dependency listed in apackage.jsonthat nothing references) - Duplicate exports (the same symbol exported under two names)
Auto-PR only the categories that are safe to delete mechanically. Everything else is flagged in the PR's Needs Review section, not deleted.
| Category | Action |
|---|---|
Unused internal export / type in packages/* not in any package's exports map |
Auto-remove |
Unused file in packages/* not in any exports/bin and not matched by an entry pattern |
Auto-remove |
Unused devDependency
|
Auto-remove (remove the line; verify install/build/test) |
| Duplicate export | Flag (renames are judgment calls) |
Anything in apps/*
|
Flag only. App module graphs need built workspace deps to resolve, so knip under-resolves them and produces false positives. Never auto-delete app code. |
Anything matched by a knip.jsonc entry pattern (*.doc.mjs, stories, Next.js route files) |
Never touch (entry points by design) |
Anything under packages/cli/templates/** or internal/vibe-tests/.baseline/**
|
Never touch (standalone scaffolding / reference fixtures, already ignored in config) |
| Unused / unlisted / unresolved runtime dependencies | Do NOT act. Defer to the Dependencies and Quartermaster roles |
Before deleting any export, type, or file, confirm all of:
- It is reported by the detector's JSON output in an auto-removable category above.
- A repo-wide search (
git grep) for the symbol/file basename returns no references outside its own definition. - It is not a dynamic import, StyleX codegen output, CLI template source, or a name referenced from a non-TS surface (
.md,.mjsdoc, JSON, config). Static analysis misses these. - Removing it leaves
pnpm buildandpnpm testgreen.
If any check fails, flag it, do not delete it.
- Touch runtime dependencies (unused/unlisted/unresolved deps). That is Dependencies + Quartermaster
- Delete anything in
apps/*(flag only) - Component convention fixes (theming, API, a11y, export hygiene). That is Component Auditor
- CI fixes. That is QA
- Merge or approve PRs. Humans do that
- Refactor passing code or restructure modules. Removal only, no rewrites
- Add anything to the repo's own toolchain (
package.json, lockfile, CI). The detector stays out-of-repo - File issues for individual findings. Findings live in the run log and the PR body
- Clone the wiki fresh; confirm this role is still assigned to your human in Night Watch Roles. If not, disable the cron job and stop.
- Apply the business-hours guard. If business hours, NO_REPLY.
- Check
memory/xds-night-watch-state.jsonfordeadCode.lastRunAt. If it is from today (PST), skip and NO_REPLY. - On the
xdsnode, fetch latestorigin/mainand create a worktree from it (for the PR branch). - Bootstrap the out-of-repo tools: run
bash memory/xds-night-watch/deadcode-tools/bootstrap.sh(copied to the node). This installs knip in the tools dir if needed.
knip needs a checkout with node_modules to resolve imports. The shared main checkout has them; the analysis is read-only, so point the detector at a checkout that is installed:
TOOLS=/vercel/sandbox/repos/xds-nightwatch-tools/deadcode
node "$TOOLS/check-deadcode.mjs" --repo /vercel/sandbox/repos/xds --reporter json > /tmp/deadcode.jsonParse the JSON. Bucket every finding into the confidence tiers above. Discard the runtime-dependency and apps/* buckets (flag-only).
For each candidate export/type/file, run the four-point high-confidence deletion rule (git grep for references, rule out dynamic/codegen/template/non-TS use). Demote anything that fails to the Needs Review list. Make the actual edits in your worktree, not the shared checkout.
- Delete unused files; remove unused exports/types from their source; drop unused
devDependencieslines. - Run
pnpm install(if a devDependency was removed), thenpnpm build && pnpm testin the worktree. - If the build or tests break, revert the offending removal and keep the rest. One bad removal must not block the batch.
- One PR per night. Branch: a plain semantic name,
chore/dead-code-YYYY-MM-DD(nonavi/prefix; the commit guard blocks agent-named branches on this repo). - Commit with
--no-verify(husky hooks hang in worktrees). Commits use the node's default git author. - Title:
chore: remove dead code (YYYY-MM-DD). Body: list what was removed, grouped by category, with a short justification per group. Put everything flagged (duplicates,apps/*, anything that failed verification) under a Needs Review heading. -
Public-repo hygiene: scrub the branch, commit, and PR body of internal refs and agent fingerprints (see Night Watch Overview Principle 6 and the repo's leak rules). The only permitted footer is
Night Watch — Dead Code. - Publish ready for review (not draft).
- If nothing is auto-removable, do not open a PR. Log findings and update state.
Same as the Component Auditor: record the pushed HEAD sha, schedule a one-shot recheck ~5 min out, check gh pr checks, fix CI failures in place (SHA-collision guard first), max 3 attempts, then hand off to daytime review.
- Log findings and actions to
memory/xds-night-watch/{date}.mdunder a## Dead Codesection. - Update
memory/xds-night-watch-state.json.
{
"deadCode": {
"lastRunAt": "ISO timestamp",
"prsFiled": ["#NNNN"],
"lastRemovedCount": { "files": 0, "exports": 0, "types": 0, "devDependencies": 0 },
"flaggedForReview": ["packages/core/src/foo.ts:Bar (duplicate export)"]
}
}knip.jsonc (in the operator's workspace) is the source of truth for what counts as an entry point. When a finding is a false positive because a legitimate entry pattern is missing (a new codegen file type, a new app route convention), fix knip.jsonc first, then re-run. Do not silence a real category with a blanket ignore. Keep the workspace copy and the node copy in sync via bootstrap.sh.
- knip's parser reserves a large virtual buffer; on small, swapless hosts the runner sets
vm.overcommit_memory=1when permitted. If you see "Array buffer allocation failed", run on a larger host or with privileges to set that sysctl. - The detector is a report, run out-of-repo. It never touches the repo toolchain and never blocks anyone.
- knip needs
node_modulesin the target checkout; a bare worktree without an install will not resolve. Point--repoat an installed checkout.
| Date | Result |
|---|---|
| 2026-07-13 | Role created. Out-of-repo knip tooling built and validated on the xds node (public API, CLI templates, and vibe-test baselines correctly excluded; real findings: unused internal exports, types, and devDependencies). |