Skip to content

chore(ci): modernize Node matrix — drop EOL versions, target Active LTS + Current - #17

Merged
AlbSar merged 1 commit into
docs/embedded-web-terminal-specfrom
chore/ci-node-modernization
May 20, 2026
Merged

chore(ci): modernize Node matrix — drop EOL versions, target Active LTS + Current#17
AlbSar merged 1 commit into
docs/embedded-web-terminal-specfrom
chore/ci-node-modernization

Conversation

@AlbSar

@AlbSar AlbSar commented May 20, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Drop Node 18/20/22, add Node 24 + 26. Bump engines, fix better-sqlite3 native binding install, realign 7 dogfood test files. Local: 15,534 tests pass, 0 fail.

Base = docs/embedded-web-terminal-spec (PR #16) so PR #16's test/vitepress/secret-baseline fixes are inherited. Auto-converts to base=main once PR #16 merges.

Why this PR exists

Sprint 175 PR #16 CI dogfood produced 230+ test failures across the entire matrix. Root cause was not Sprint 175 work — it was systemic CI rot.

Node Status (May 2026) We were testing? EOL gap
v18 (Hydrogen) EOL Apr 2025 ❌ Yes 1+ year dead
v20 (Iron) EOL Mar 2026 ❌ Yes 2 months dead
v22 (Jod) Maintenance EOL May 2026 ❌ Yes this month
v24 (Krypton) Active LTS until May 2027 ❌ NO not in matrix
v26 Current (latest, May 5 2026) ❌ NO not in matrix

The matrix burned three slots on dead-or-dying releases and never touched Active LTS or Current. better-sqlite3@12.10.0 (May 12 2026 — eight days ago) explicitly removed Node 20/23 prebuilds and added Node 26, so the old matrix was guaranteed to fail post-12.10.0 regardless.

What changed

Workflow matrix bump (all 7 yml files)

  • Matrix [18.x, 20.x, 22.x][24.x, 26.x] across test-core, test-orchestra, test-cli, test-remaining, dashboard build.
  • Fixed '22.x' / '20''24.x' / '24' across typecheck, security, test-docs-scripts, test-dashboard, test-windows, coverage, build, docs, publish, release, secret-scan, cross-platform-e2e.
  • Dashboard artifact upload conditional: matrix.node-version == '22.x''24.x' so the LTS run ships the artifact.

package.json

  • engines.node: >=18.0.0>=24.0.0. Breaking change by design — Node 18/20/22 users see a clear error at npm install time (engineStrict warning) instead of a runtime crash later.
  • better-sqlite3: ^12.9.0^12.10.0 (Node 26 prebuilds added, Node 20/23 cleanup).
  • New script ci:rebuild-native: npm rebuild better-sqlite3 --ignore-scripts=false. Required because the project's .npmrc sets ignore-scripts=true (Sprint 167 H3 supply-chain hardening); npm ci honours that and skips better-sqlite3's install script, so the native binding never lands without an explicit rebuild. Targeted to the one native dep that needs it.

Workflows: new step npm run ci:rebuild-native after every npm ci

~5-second cost per job. Without it the binding is missing and 200+ tests collapse on Database instantiation.

Runtime guard (src/cli/entry.ts)

< 18< 24. Error message updated to mention Active LTS.

Test realignments (7 files)

  • tests/github/ci-workflow.test.ts, tests/github/workflows/ci.test.ts, tests/github/workflows/release.test.ts — workflow assertions against the new matrix and fixed versions.
  • tests/cli/bin-entry-validation.test.ts, tests/cli/npx-compat.test.ts — engines.node and entry.ts guard assertions.
  • tests/core/nervous-enabled-integration.test.ts.deckent/config.json dogfood assertion now skipped when the file is absent (PR feat(terminal): embedded web terminal — sub-project #1/4 (spec→plan→Sprint 175) #16 made the config gitignored).

Local verification (Node 24.15.0)

Gate Result
Non-orchestra suites 475 files, 10,625 pass, 23 skip, 0 fail
Orchestra suite 205 files, 4,416 pass, 11 skip, 0 fail
Dashboard suite 23 files, 493 pass, 0 fail
tsc --noEmit clean
npm run build all binaries present + shebang
VitePress build complete
secret-baseline.mjs 0 unallowlisted secrets

Total: 15,534 tests pass, 0 fail locally.

Expected CI delta

  • Matrix runs halve: 3 Node × 4 test suites = 12 entries → 2 Node × 4 = 8 entries.
  • Coverage + Build chains unblocked (they were skipped on main because matrix tests fail).
  • better-sqlite3 native binding now installs in every job (was the silent cause of Database errors).
  • All Node-version-pinned dogfood tests realigned — no test assertions reference EOL Node anymore.

Test plan

  • npm install clean on Node 24
  • Full vitest suite green locally
  • npm run build produces all expected binaries
  • VitePress + secret-baseline + tsc gates green
  • CI on this PR: all matrix entries green
  • Coverage Report job runs (was perpetually skipped on main due to matrix test failures)
  • Build job runs (same reason)
  • Manual smoke: deckent --version on Node 24 + Node 26

🤖 Generated with Claude Code

…TS + Current

Sprint 175 PR #16 CI dogfood surfaced 230+ test failures across the entire
matrix. Root cause was not Sprint 175 work — it was systemic CI rot.

## Why now

| Node | Status (May 2026) | We were testing? |
|------|---------------------|---------------------|
| v18 (Hydrogen) | EOL Apr 2025 — 1+ year dead | ❌ Yes (wasted) |
| v20 (Iron) | EOL Mar 2026 — 2 months dead | ❌ Yes (wasted) |
| v22 (Jod) | Maintenance EOL May 2026 — this month | ❌ Yes (wasted) |
| **v24 (Krypton)** | **Active LTS (until May 2027) — production target** | ❌ NO (untested) |
| v26 | Current (latest) | ❌ NO (untested) |

The matrix burned three slots on dead-or-dying releases while never
touching Active LTS or Current. better-sqlite3 v12.10.0 (released May 12,
2026) explicitly removed Node 20/23 prebuilds and added Node 26 — so the
old matrix was guaranteed to fail post-12.10.0 anyway.

## Changes

- All 7 workflows (`ci.yml`, `dashboard-build.yml`, `cross-platform-e2e.yml`,
  `docs.yml`, `publish.yml`, `release.yml`, `secret-scan.yml`):
  - Matrix `[18.x, 20.x, 22.x]` → `[24.x, 26.x]` (test-core, test-orchestra,
    test-cli, test-remaining, dashboard build)
  - Fixed `'22.x'` / `'20'` → `'24.x'` / `'24'` (typecheck, security,
    test-docs-scripts, test-dashboard, test-windows, coverage, build,
    docs, publish, release, secret-scan, cross-platform-e2e)
  - Dashboard artifact upload condition: `matrix.node-version == '22.x'`
    → `'24.x'` so the LTS run ships the artifact.

- `package.json`:
  - `engines.node`: `>=18.0.0` → `>=24.0.0`. Breaking-change-by-design for
    OSS GA — Node 18/20/22 users get a clear error instead of a runtime
    crash later (npm shows `engineStrict` warning at install time).
  - `better-sqlite3`: `^12.9.0` → `^12.10.0` (Node 26 prebuilds, Node 20/23
    cleanup). Verified locally: 12.10.0 ships prebuilds for the new
    matrix; no native compile required at install time.
  - New script `ci:rebuild-native: npm rebuild better-sqlite3 --ignore-
    scripts=false`. Required because `.npmrc` sets `ignore-scripts=true`
    (Sprint 167 H3 supply-chain hardening); `npm ci` honours that and
    skips better-sqlite3's `prebuild-install || node-gyp rebuild`, so
    the native binding never lands without an explicit rebuild step.
    Targeted to the one package that needs it — the .npmrc guard for
    every other dependency stays intact.

- All 7 workflows: new step `npm run ci:rebuild-native` after `npm ci`.
  Five-second cost per job; without it the binding is missing and 200+
  tests collapse on `Database` instantiation.

- `src/cli/entry.ts`: runtime Node guard `< 18` → `< 24`. Error message
  updated to mention Active LTS.

- 7 test files realigned:
  - `tests/github/ci-workflow.test.ts`, `tests/github/workflows/ci.test.ts`,
    `tests/github/workflows/release.test.ts` — workflow assertions
    against the new matrix and fixed versions.
  - `tests/cli/bin-entry-validation.test.ts`, `tests/cli/npx-compat.test.ts`
    — engines.node and entry.ts guard assertions.
  - `tests/core/nervous-enabled-integration.test.ts` — `.deckent/config.
    json` dogfood-only assertion now skipped when the file is absent
    (PR #16 made the config gitignored).

## Local verification (Node 24.15.0, the current Active LTS)

| Gate | Result |
|------|--------|
| Non-orchestra suites | 475 files, **10,625 pass**, 23 skip, **0 fail** |
| Orchestra suite | 205 files, **4,416 pass**, 11 skip, **0 fail** |
| Dashboard suite | 23 files, **493 pass**, **0 fail** |
| `tsc --noEmit` | clean |
| `npm run build` | dist/cli/{index,entry}.js, dist/mcp/server.js, dist/index.js all present with shebang |
| VitePress build | complete |
| `secret-baseline.mjs` | 0 unallowlisted secrets |

Total: **15,534 tests pass, 0 fail**.

## Baseline note

This PR is based on `docs/embedded-web-terminal-spec` (PR #16). PR #16's
test/vitepress/secret-baseline fixes are inherited; once PR #16 merges
to main, this PR's base becomes main automatically with no conflict.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@AlbSar AlbSar closed this May 20, 2026
@AlbSar AlbSar reopened this May 20, 2026
@AlbSar
AlbSar merged commit 2fab023 into docs/embedded-web-terminal-spec May 20, 2026
@AlbSar
AlbSar deleted the chore/ci-node-modernization branch May 20, 2026 07:19
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