Skip to content

Downgrade lint-staged 17→16, enable engine-strict#90

Merged
lfernandez79 merged 3 commits into
masterfrom
chore/lint-staged-v16-engine-strict
Jun 15, 2026
Merged

Downgrade lint-staged 17→16, enable engine-strict#90
lfernandez79 merged 3 commits into
masterfrom
chore/lint-staged-v16-engine-strict

Conversation

@lfernandez79

Copy link
Copy Markdown
Owner

Summary

  • Downgrade lint-staged from ^17.0.4 to ^16.4.0 so its declared engines field matches our actual Node floor (≥20.19). v17 claimed Node ≥22.22.1, which blocked us from turning on engine-strict.
  • Remove the direct listr2 ^10.2.1 devDep pin — leftover from an old upgrade attempt; lint-staged@16 brings in a compatible transitive automatically. The pinned v10 also declared Node ≥22.13.
  • Enable engine-strict=true via .npmrc. Now npm ci on Node <20.19 fails cleanly at install time rather than silently warning and crashing later inside listr2.

This is the follow-up I called out in 8f6f816 — closes the gap where the engines.node field was advisory only.

Test plan

  • Local npm ci clean under engine-strict=true on Node 20.20.2 (source ~/.nvm/nvm.sh && nvm use 20 && rm -rf node_modules package-lock.json && npm install succeeds with 0 vulnerabilities)
  • npm run lint passes
  • npm test passes (coverage report unchanged)
  • npm run build succeeds
  • npm run smoke passes (real Chrome smoke against built bundle)
  • npx lint-staged --debug against a staged src/ file runs eslint --fix + prettier --write end-to-end, then prevents an empty commit (expected v16 behavior when format pipeline produces no real diff)
  • CI green (this PR's required checks: ci + Netlify deploy preview)

Notes

A pre-existing js-yaml ≤ 4.1.1 audit finding (GHSA-h67p-54hq-rp68) showed up during install — not introduced by this PR, surfaced via the cleaner lockfile regen. Worth a separate Dependabot pass.

🤖 Generated with Claude Code

lfernandez79 and others added 3 commits June 15, 2026 13:26
lint-staged@17 declares engines: { node: ">=22.22.1" } even though
it runs fine on Node 20. That overly-conservative range blocked us
from enabling `engine-strict=true` (which would have surfaced the
Husky-on-Node-18 crash earlier). v16 declares Node ≥20.17, which
matches our actual floor.

Also remove the direct `listr2` devDep pin (^10.2.1) — it was a
holdover from an old lint-staged upgrade attempt, and v10 itself
declares Node ≥22.13. lint-staged@16 brings in a compatible listr2
as a transitive automatically.

With these in place, `engine-strict=true` (added via .npmrc) now
fails installs cleanly on Node <20.19, instead of silently warning
and crashing inside listr2 later.

Verified locally on Node 20.20.2:
- `npm ci` clean under engine-strict
- lint / test / build / smoke all pass
- `npx lint-staged --debug` runs eslint --fix + prettier --write
  pipeline on a staged src/ file correctly

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`networkidle0` waits for 500ms of zero network activity, which never
arrives on the GH Actions runner — `vite preview` keeps a few
connections alive that the runner is slow enough to register as
ongoing. PR #90's first CI run timed out at 15s before the page
even finished loading.

`load` is the right signal: the document + subresources are done,
the module script has finished its top-level eval, React has
mounted the tree. The existing 1500ms post-load delay still lets
the Vanta useEffect run, so the original `(0, sA.default) is not a
function` regression is still caught (re-verified locally against
the pre-fix App.jsx — smoke fails with the same TypeError).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The first CI run on this branch stayed pegged on the smoke step
for 4+ minutes after passing/failing — Node never exited cleanly
after `browser.close()` + `preview.kill("SIGTERM")`. Something
(child pipes, residual puppeteer handles, vite preview's
grandchild) was keeping the event loop alive.

Add three guardrails:
- 90s overall watchdog that `process.exit(1)`s if we don't reach
  a verdict in time.
- Explicit `process.exit(code)` on both success and failure paths
  (no more relying on "the event loop will drain").
- SIGKILL backup 1.5s after SIGTERM, in case the preview ignores
  the polite signal.

Verified locally: positive case 3.1s, negative case 3.0s, both
exit with the correct code. Watchdog never trips.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@lfernandez79 lfernandez79 merged commit eb4f0dc into master Jun 15, 2026
9 checks passed
@lfernandez79 lfernandez79 deleted the chore/lint-staged-v16-engine-strict branch June 15, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant