Public: anyone can read this; the crew can change it.
Hollow work does not pass the gate: an action no surface calls, or a screen no page links to, is named and the check goes red #681
Check · Review · Land · Live done — Landed and live in production.
Closes #615
shipped production is serving it for issue #615 — its issue is already done deploy e2a191c
What a person sees. A pull that adds an action nobody can call, or a screen nobody can get to, turns the gate red, and the failing line names it and says what to do.
What is in it
scripts/hollow.ts: the audit, and a command.bun scripts/hollow.tsprints one line per problem and exits 1.scripts/hollow-allow.ts: what main carries today, each entry under the issue that owns it.test/hollow.test.ts, inGATE: 25 tests. The audit over this tree, the command, and each rule on small trees; thespawnForgeshape and the fleet-graph shape are both there.src/actions/origins.ts:mirrorRepois removed. The audit named it, and nothing called it, tests included.- CLAUDE.md and README.md: the rule, a paragraph each.
How it decides
- An action. Every exported function under
src/actions/. Reach starts at every declaration undersrc/http,src/web,src/crew,src/cliandsrc/tuiand at each module's top-level statements, and follows the names a reached declaration mentions, declaration by declaration, through imports and re-exports. An action called by another action or throughsrc/fleet/is reached; one that only its tests call is not. - A screen. A GET route with no parameter whose handler can draw the page (
pageinweb/layout.ts). On main that is 26 routes, and no API route, fragment, redirect or file is among them. It is linked when its path stands in a string of a module that a reachable page uses, starting from/and from every page whose path takes a parameter. A page that links only to itself, or two that link only to each other, are still orphans.
Where it departs from the issue's wording, and why
- "the diff against
main". The forge runs the check in a directory with no.git, so there is nothing to diff. The allow-list is the baseline instead: whatever is hollow and not listed came with the pull. An entry that is no longer hollow fails the check, so the list only shrinks. - "nothing under src/http ... imports". Read as a direct import from those five directories, that rule named 22 functions on main (at 596540a), and 20 of them are called: the six
require*helpers inactions/access.tsandoriginPushonly ever by other actions,setIssueLabels,requeueRepoRunandspawnForgethroughsrc/fleet/andsrc/spawn/, and ten are helpers that a called function of the same file uses. The audit follows the calls instead. - Screens are an addition, asked for by the steward: the fleet graph was the other hollow thing on main.
- Where it runs. As a test in
GATE, the wayscripts/tree.tsandscripts/gate.tsdo, soforge.jsonis unchanged andbun testcatches it too.
What it found on main
| orphan | what it is | here |
|---|---|---|
src/actions/origins.ts#mirrorRepo | dead: no caller in src/ or test/ | removed |
src/actions/origins.ts#resetConnectLimit | a test seam, called by 17 test files | allowed under #685 (new) |
GET /fleet/graph | a page no page links to | allowed under #448 |
spawnForge is no longer hollow: src/spawn/door.ts calls it, and the API and the MCP call the door. Cutting those two imports in memory makes the audit name spawnForge and childDirOf again.
Not touched. The release workflow and the chart. Wiring this into the release workflow is the owner's choice; the command is bun scripts/hollow.ts.
Limits
- Names are followed by spelling, not by scope, and a namespace or dynamic import reaches the whole module: where it cannot tell, an action counts as called.
- Everything under the five surface directories counts as a caller, routed or not.
- A route with a parameter is not judged: its links are computed from rows.
- A constant holding a wrapped function (
export const x = wrap(() => ...)) is not judged. - It imports
typescript, the dev dependency the gate already runs astsc, to read the sources.
Verified
bun x tsc --noEmitclean.bun run checklocally: 1379 tests in 98 files, 2 failed, both also failing on a pristine main at the time (the #230 studio test, since fixed on main by #696, and a crew test that fails only on macOS). After merging main again:test/hollow.test.ts,test/check-list.test.ts,test/tree.test.tsand the #230 test pass.- On the real tree, in memory: linking
/fleet/graphfrom the board clears it; cutting the spawn door's imports namesspawnForge.
🤖 Generated with Claude Code
Closes #615
Work in progress: the audit (
scripts/hollow.ts) is here; the gate test, the allow-list entries and the fixes for what it finds on main follow in this pull.🤖 Generated with Claude Code