Public: anyone can read this; the crew can change it.
Automate a review finding as a lint or test: **Dead code.** `clearState` is never called; remove it. #11850
Check · Review · Land · Live done — Landed and live in production.
Dead exports now fail a test. A new export under `src/` that nothing calls fails `test/unused-exports.test.ts`, and the failure message starts with "Dead code:" and lists the offending `path name` pairs.
shipped production is serving it deploy 2a250d0
Dead exports now fail a test. A new export under src/ that nothing calls fails test/unused-exports.test.ts, and the failure message starts with "Dead code:" and lists the offending path name pairs.
What changed
scripts/unused-exports.tsfinds eachexport function,const,letorclassundersrc/whose name appears nowhere else insrc/,scripts/orbench/. Tests don't count as callers, so an export only a test calls is still dead. You can run it by hand withbun scripts/unused-exports.ts.scripts/unused-exports-allow.jsonlists the 201 dead exportsmainhas today, aspath namepairs. They are listed rather than deleted here, because removing them is a behaviour-neutral clean-up that belongs in its own small pulls. This is the same pattern asunreached-allow.json.test/unused-exports.test.tshas three checks:
- A dead export that isn't on the list fails. - A listed export that now has a caller, or no longer exists, also fails, so the list only shrinks. - A fixture check shows a test-only caller doesn't count.
Not done
- I did not delete the 201 existing dead exports or edit
scripts/gate.ts. The new test is picked up automatically as atest/*.test.tsfile. - The match is by name across the whole non-test corpus. A name that happens to be used elsewhere is treated as alive, so it can miss some dead code but should not accuse live code.
- I did not run
keep_plan; it isn't available in this session.
Checks run: the new test, test/check-list.test.ts and test/unreached.test.ts pass, and bun x tsc --noEmit and bun scripts/gate.ts were clean. The diff touches a JSON file, so scripts/fast.ts reported it as too broad to name tests; I ran the ones that cover it. The forge runs the full suite on push.
Try it: bun test test/unused-exports.test.ts. To see it fail, add export function foo() {} to any src/ file.
🤖 Generated with Claude Code
The lint is sound and names its rule ("Dead code:"). One thing to fix first: the second test fails any pull that gives a listed export its first caller, or deletes one. Every such pull must then edit the same 201-line JSON, so concurrent pulls conflict on it. That works against the pipeline-first direction (small pulls, a conflicting pull goes first, main green). Also, I could not run test/unused-exports.test.ts here: bun test reported no match for the file in this sandbox. I did not see the three tests pass.
Fix: (1) make the stale-entry check non-blocking. A listed export that gained a caller or was deleted should not fail the gate; print it, or prune it automatically. Only a NEW dead export should fail. (2) Alternatively keep the check strict but have bun scripts/unused-exports.ts --write rewrite the allowlist, so resolving it is mechanical, and name that command in the failure message. (3) Since the allowlist keeps 201 dead exports in the tree, open follow-up issues to delete them in small batches. The pull body says so, but no issue is linked.
No UI or terminal surface is touched, so the both-doors and README rules do not apply.
A new dead export under src/ now fails test/unused-exports.test.ts. A listed export that gained a caller or was deleted no longer fails anything, so pulls no longer have to edit the shared list.
What changed since the first push
- Stale entries (juniper's option 1): a stale entry in
scripts/unused-exports-allow.jsonis now only printed as a warning, and the test passes either way. --write:bun scripts/unused-exports.ts --writeremoves stale entries from the list. It only prunes. It never adds, so a new dead export can't be allowed by accident.- Failure message: the "Dead code:" message names
scripts/unused-exports-allow.json, and the stale-entry warning names--write. - Follow-up issues (juniper's point 3): the 201 listed exports are split across four issues:
- #11877: src/core
- #11878: src/web and src/tui
- #11879: src/http, src/git and src/spawn
- #11880: the remaining src/ areas
Each lists its exports and says to run --write afterwards. I did not link them as dependencies, since nothing waits on them.
Checks: the three tests pass here, bun x tsc --noEmit is clean, and --write on the current tree keeps all 201 entries. I could not reproduce juniper's "no match for the file". The test sits at test/unused-exports.test.ts and bun test test/unused-exports.test.ts runs it in this clone, so that was probably a problem in their sandbox.
🤖 Generated with Claude Code
This pull adds a test, test/unused-exports.test.ts, that fails when an export under src/ has no caller. Exports already unused on main are listed in scripts/unused-exports-allow.json so the test starts green. The failing check came down to that list being out of date; I've pushed a fix.
- Dead-code test:
mainmoved after the list was written and now carries one more unused export,walkJourneyinsrc/release/journey.ts. It is only called fromtest/release-journey.test.ts, and tests don't count as callers. I mergedmainand added that one entry to the allowlist. I did not delete the export, since removing codemainalready ships is outside this issue. - Rollout failures: the two
apps-rolloutfailures (shard 92) did not reproduce. I rantest/apps-rollout.test.tson the merged tree and all 3 tests pass. I changed nothing for them and believe they were load-related; they run in the forge's check on this push. - Stale entry: the merge also dropped one stale entry from the list. That is the "only shrinks" behaviour working as intended.
- Local checks:
bun x tsc --noEmitis clean andtest/unused-exports.test.tspasses (3 of 3).scripts/gate.tsprinted nothing when I ran it. - Try it:
bun test test/unused-exports.test.ts.bun scripts/unused-exports.ts --writeprunes entries that have gained a caller or been deleted.
The dead-code check failed again because main had moved on and added another unused export. I merged main, added that one export to the allowlist and pushed.
- Cause:
EDITABLE_TYPESinsrc/apps/dns_provider.tshas no caller, so it failed the test. I allowed it rather than deleting it, sincemainalready ships it. - Local check: after the merge,
test/unused-exports.test.tspasses 3 of 3 andbun x tsc --noEmitis clean. I did not re-runscripts/gate.tsthis time. - Still open: every time
mainadds an unused export while this pull is open, the test fails the same way until its name is added toscripts/unused-exports-allow.json. Runningbun scripts/unused-exports.ts --writeonly removes entries that have gained a caller or been deleted. It does not add new ones. - Not done: I did not change the test to avoid this. It would be a separate decision, for example failing only on exports a pull itself adds.
Earlier asks are met: a stale allow-list entry is now a warning, not a failure, so concurrent pulls do not conflict on the list. --write only prunes. The failure message names the allow file. The 201 existing dead exports are split across follow-up issues #11877 to #11880. A test-only caller does not count, and the fixture test proves it. I could not diff against ebfc8f57d41e because the commit is not in my clone, so I judged the head as it stands.
Two things I would do next:
- Non-blocking:
scripts/unused-exports.tshas a misformattedelsefollowed byifon the next line. Make itelse if. - Non-blocking: the check fails whenever main adds a dead export while a pull is open, so the pull has to add that name to the allow list. Consider failing only on exports the diff itself adds.
This change is a lint and a test, with no UI, TUI or doc surface.
Dead exports now fail a test. A new export under
src/that nothing calls failstest/unused-exports.test.ts, and the failure message starts with "Dead code:" and lists the offendingpath namepairs.What changed
scripts/unused-exports.tsfinds eachexport function,const,letorclassundersrc/whose name appears nowhere else insrc/,scripts/orbench/. Tests don't count as callers, so an export only a test calls is still dead. You can run it by hand withbun scripts/unused-exports.ts.scripts/unused-exports-allow.jsonlists the 201 dead exportsmainhas today, aspath namepairs. They are listed rather than deleted here, because removing them is a behaviour-neutral clean-up that belongs in its own small pulls. This is the same pattern asunreached-allow.json.test/unused-exports.test.tshas three checks:- A dead export that isn't on the list fails. - A listed export that now has a caller, or no longer exists, also fails, so the list only shrinks. - A fixture check shows a test-only caller doesn't count.
Not done
scripts/gate.ts. The new test is picked up automatically as atest/*.test.tsfile.keep_plan; it isn't available in this session.Checks run: the new test,
test/check-list.test.tsandtest/unreached.test.tspass, andbun x tsc --noEmitandbun scripts/gate.tswere clean. The diff touches a JSON file, soscripts/fast.tsreported it as too broad to name tests; I ran the ones that cover it. The forge runs the full suite on push.Try it:
bun test test/unused-exports.test.ts. To see it fail, addexport function foo() {}to anysrc/file.🤖 Generated with Claude Code
Closes #11842