Measured while implementing #127. Filed unassigned: the #127 ruling scoped that PR to the check only and forbade changing declared values.
The finding
#127 and #121 both describe the Node floor as three declarations. There are four:
| File |
engines.node |
package.json |
>=22 |
apps/docs/package.json |
>=22.0.0 |
tools/ci-scripts/package.json |
>=20.0.0 |
.node-version |
22 (version-manager pin) |
tools/ci-scripts is a real workspace package — pnpm-workspace.yaml includes tools/*, and it owns the test task that the required build job runs. Its floor disagrees with the other two by a whole major.
Is it wrong?
Not obviously, which is why this is a decision rather than a fix. tools/ci-scripts has no dependencies of its own — it is one zero-dependency .mjs that spawns the scripts in .github/scripts/ — so >=20.0.0 is very plausibly an accurate statement about that package in isolation. The question is whether a single-lockfile workspace should hold one floor for the whole repo or a per-package floor that means what it says.
Both answers are defensible:
- One floor. The workspace installs under one Node, contributors have one
.node-version, and a per-package floor that nothing installs separately is a claim nobody can act on. Bump it to >=22 and keep the declarations uniform.
- Per-package floors. They are accurate, and if
tools/ci-scripts is ever run outside this repo the floor is real information. Keep it, and say so somewhere, so the next person does not "fix" the inconsistency.
What the #127 gate does about it today
Nothing, deliberately, and it says so out loud. The gate governs package.json and apps/docs/package.json — the surface the card named — and it now discovers every workspace package.json and reports any declaring an engines.node it does not govern. That finding is advisory, never blocking, so the gate stays green on main while the blind spot is visible on every run:
ℹ️ 1 note(s), reported and not blocking:
- **ungoverned** — tools/ci-scripts/package.json declares engines.node ">=20.0.0",
which this gate does not check — it governs package.json and apps/docs/package.json only
An explicit file list that silently covered two of three declarations would have been the same structurally-silent shape #127 exists to end, so the gate declares its own coverage instead of implying it.
Whichever way this is decided, the follow-up is one line: either bump tools/ci-scripts to >=22 and add it to DECLARATION_FILES in .github/scripts/check-node-floor.mjs, or leave the value and record the intent.
Generated by Claude Code
Measured while implementing #127. Filed unassigned: the #127 ruling scoped that PR to the check only and forbade changing declared values.
The finding
#127 and #121 both describe the Node floor as three declarations. There are four:
engines.nodepackage.json>=22apps/docs/package.json>=22.0.0tools/ci-scripts/package.json>=20.0.0.node-version22(version-manager pin)tools/ci-scriptsis a real workspace package —pnpm-workspace.yamlincludestools/*, and it owns thetesttask that the requiredbuildjob runs. Its floor disagrees with the other two by a whole major.Is it wrong?
Not obviously, which is why this is a decision rather than a fix.
tools/ci-scriptshas no dependencies of its own — it is one zero-dependency.mjsthat spawns the scripts in.github/scripts/— so>=20.0.0is very plausibly an accurate statement about that package in isolation. The question is whether a single-lockfile workspace should hold one floor for the whole repo or a per-package floor that means what it says.Both answers are defensible:
.node-version, and a per-package floor that nothing installs separately is a claim nobody can act on. Bump it to>=22and keep the declarations uniform.tools/ci-scriptsis ever run outside this repo the floor is real information. Keep it, and say so somewhere, so the next person does not "fix" the inconsistency.What the #127 gate does about it today
Nothing, deliberately, and it says so out loud. The gate governs
package.jsonandapps/docs/package.json— the surface the card named — and it now discovers every workspacepackage.jsonand reports any declaring anengines.nodeit does not govern. That finding is advisory, never blocking, so the gate stays green onmainwhile the blind spot is visible on every run:An explicit file list that silently covered two of three declarations would have been the same structurally-silent shape #127 exists to end, so the gate declares its own coverage instead of implying it.
Whichever way this is decided, the follow-up is one line: either bump
tools/ci-scriptsto>=22and add it toDECLARATION_FILESin.github/scripts/check-node-floor.mjs, or leave the value and record the intent.Generated by Claude Code