Repository navigation
chore: clients/cli drifts to @types/node 24.13.1 via @types/express, and verify:dep-lockstep cannot see it #2226
Description
clients/cli resolves @types/node 24.13.1 while the repo root declares and installs
24.13.3:
clients/cli/node_modules/@types/node = 24.13.1
clients/web/node_modules/@types/node = 24.13.3
node_modules/@types/node = 24.13.3 (the root declaration, ^24.12.4)
Neither client declares @types/node — #2196 consolidated it to the root. The cli copy is
hoisted transitively via @types/express, so it is constrained by nothing of ours: no range
we own governs it, and nothing pulls it forward when the root moves.
Why the guard does not catch it
verify:dep-lockstep reports OK, and it is right to. It compares only packages that a single
tsc program loads from two installs, and no one program sees both copies — so the
difference is outside its candidate set entirely. AGENTS.md says this in as many words:
A transitive copy is constrained by nothing of ours at all, and cli's
@types/node
(24.13.1against the root's24.13.3) has already diverged on exactly that.
verify:dep-lockstepdoes not catch either […] the cli@types/nodedifference goes
unreported because no one program sees both copies.
So this is a known, documented drift rather than a new discovery. Filing it because the
documentation currently states the problem without anything tracking the fix, and because two
patch versions of @types/node is the harmless end of a failure mode whose expensive end is a
type error that reproduces on one machine and not another.
Impact today
Low. It is a types-only package (no runtime code ships), the skew is two patch releases, and
npm run local:gate passes — verify:typecheck-coverage gives all 1082 tracked source files a
tsc pass. Nothing is broken right now; the concern is that nothing would tell us when it stops
being two patches.
Options
- Declare
@types/nodeinclients/cli— simplest, but re-creates the second declaration
chore: consolidate shared toolchain devDependencies into the root package.json #2196 removed, andAGENTS.mdis explicit that re-adding a root-declared package to a client
manifest re-creates the duplicate the rule exists to make impossible (chore(deps): zod 4.4 blows the tsc heap in clients/web — held at ~4.3.6 #1896). Probably wrong. - A root
overridesentry for@types/node— one declaration, still one place to bump,
and it reaches the transitive copy. Consistent with the repo's "pin a transitive with
overrides" rule. - Widen
verify:dep-lockstepso it compares installed copies of root-declared packages
directly rather than only those a sharedtscprogram loads. Catches the whole class instead
of this instance — but it is a real change to what the guard means, and would likely surface
the peer shadows in web and tui too (which currently agree with the root, so it would start
green).
(3) is the one that stops the next instance; (2) fixes this one now. They are not exclusive.
Done when
-
clients/cliand the root resolve the same@types/node - Something fails when they next diverge — either the widened guard, or a stated decision
that anoverridespin is the whole mechanism and the guard is deliberately left as-is -
npm run local:gatepasses
Found while smoke-testing the v2.5.0 payload — see the note on
#2215 (comment)
Activity
cliffhall commentedon Sep 2, 2026
Triage: Priority Low (total 4)
@types/nodeships no runtime code, the skew is two patch releases, andnpm run local:gatepasses today —verify:typecheck-coveragegives all 1082 tracked source files atscpass. This is a latent risk, not a current defect.AGENTS.md, so it is not going to surprise anyone who reads the rules before touching a manifest.bug, not security-related, no engagement, unassigned, not a sub-issue, and no milestone bonus (see the note on chore: pin browserslist past GHSA-c83g-rgw3-j3cx in clients/tui (dev-only high advisory) #2225 — it is a constant for create-flow issues).May legitimately sit. The reason to keep it on the board rather than close it is the second bullet under Done when: the value here is deciding whether
verify:dep-lockstepshould widen to see this class at all, and that decision is worth recording either way — including as an explicit "no, anoverridespin is the whole mechanism."Board: #28, Status
Todo, milestone v2.6.0.chore: address Copilot review round 1 (#2226)
chore: address Copilot review round 2 (#2226)
chore: address Copilot review round 3 (#2226)
chore: widen verify:dep-lockstep to declared cross-install copies (mo…