Skip to content

chore: drop Node 20 — an end-of-life runtime, and the only line with no second SQLite driver - #592

Merged
irparent merged 2 commits into
mainfrom
chore/drop-node-20
Sep 22, 2026
Merged

irparent merged 2 commits into
mainfrom
chore/drop-node-20

Conversation

@irparent

@irparent irparent commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

⚠️ This PR cannot merge until a required check is removed

test (20) is a required status check on main. This PR deletes the job that reports it, so GitHub will hold the PR on "Expected — waiting for status to be reported" forever. That is correct behaviour, not a failure, and it is not something to merge past with admin rights.

Settings → Branches → main → Require status checks to pass:

The required count goes from eleven to twelve. Nothing else changes.

The floor is 22.13, not 22.0 — and that was a correction

The first draft of this PR said >=22.0.0, and its own justification did not survive review. The reason given for dropping Node 20 was that it is the only supported line with no second storage driver. But node:sqlite arrives in 22.13.0 — Iris's own NODE_SQLITE_MIN constant — so Node 22.0 through 22.12 have no fallback either. At >=22.0.0 the guarantee would still have been false, for thirteen Node releases.

>=22.13.0 makes it true: every supported runtime ships the built-in driver, so the seam added in 0.15.0 always has something to fall back to when the native addon will not load. It costs nothing — 22.13.0 shipped 2025-01-06 and the current 22.x line is 22.23.2 — and it is the number already planned as the eventual floor.

Why Node 20 goes

It is end of life. Node 20 hit its end date on 2026-04-30 and has had no security fixes in the five months since. Iris has gone on declaring >=20.0.0 and testing it in CI throughout — a promise the runtime itself stopped keeping.

It is the only supported line with no fallback driver. The storage driver seam in 0.15.0 exists so a native addon that will not load is a slower start rather than a dead one. The fallback is node:sqlite, which needs Node 22.13 or later. On Node 20 there was never a second driver — the seam is a no-op there, and a missing prebuild is still fatal.

It is the entire Linux half of Dependabot #308. better-sqlite3 13 declares engines: node >=22 and segfaults inside new Database() on Node 20; on Node 22, 24 and 25 it opens and closes a database cleanly. Measured on Ubuntu 24.04 / glibc 2.39, the same OS and C library ubuntu-latest runs:

Node N-API better-sqlite3 13.0.3
20.20.2 9 SIGSEGV inside new Database()
22.23.2 10 exit 0
24.21.0 10 exit 0

To be clear about what this PR does not do: it does not merge #308. Upstream WiseLibs/better-sqlite3#1514 reports version 13 crashing on darwin-arm64 on Node 22, which the table above shows is fine on Linux. The macOS cell added in #591 is what decides that bump. This PR removes the reason that was never about the crash.

What changed

Surface Change
package.json, packages/init/package.json engines.node >=20.0.0 → >=22.13.0
.github/workflows/ci.yml matrix is Node 22 and 24 native, both on the built-in driver, plus the macOS cell
.github/workflows/devto-crosspost.yml runner Node 20 → 22
README.md the requirement line, and the Node.js section — which now says why 22 is the floor rather than only that it is
packages/python/README.md quickstart comment (Node 20+) → (Node 22+)
CONTRIBUTING.md required-checks table: test (20) → test (24)
tests/unit/storage/driver.test.ts the comment naming which cell exercises the no-built-in branch; it is the Node 22.0–22.12 user now, not a CI cell
CHANGELOG.md an Unreleased section: the removal, and the CI change from #591, with the required-check names spelled out for anyone pinning them

Gates

llms:check, changelog:check, version:check, claims:check-hardcoded, typecheck and lint all green locally; tests/unit/storage/driver.test.ts 10/10. No source behaviour changed — the only non-documentation edits are engines, workflow runners, and one test comment.

The version stays 0.16.0; raising the floor is a breaking change and belongs to the next release, which the Unreleased section is now holding.

🤖 Generated with Claude Code

…no second SQLite driver

Node 20 reached end of life on 2026-04-30 and has had no security fixes
since. Iris has kept declaring `>=20.0.0` and testing it in CI for the five
months after, which is a promise the runtime itself stopped keeping.

It is also the one supported line with no fallback. `node:sqlite` needs
Node 22.13 or later, so the storage driver seam added in 0.15.0 — native
addon, built-in on failure — has only ever had one driver on Node 20. A
prebuild that will not load there is still a dead start.

And it is the whole of what blocks Dependabot #308: better-sqlite3 13
declares `engines: node >=22` and segfaults inside `new Database()` on Node
20 (N-API 9) while returning cleanly on 22, 24 and 25. Dropping 20 does not
merge that bump — the macOS cell added in #591 decides it, since upstream
reports a darwin-arm64 crash on Node 22 that a Linux matrix cannot see —
but it removes the reason that had nothing to do with the crash.

Surfaces: `engines` in the server and @iris-eval/init, the CI matrix
(22 and 24 native, both on the built-in, plus macOS), the dev.to crosspost
workflow's runner, the README's requirement line and its Node.js section,
the Python client's quickstart, CONTRIBUTING's required-checks table, and
the storage driver test's comment about which cell exercises the fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
website Ready Ready Preview Sep 22, 2026 4:03pm UTC

@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Iris gate — 1 of 2 tripped --fail-on detector_veto

iris-eval ingest: 3 stored, 1 tripped --fail-on detector_veto (2 of 3 evaluated in dataset "release-gate")

Trace Basis Rules Evidence
a7e22b6bfe80a944b9ccdd2074ae80dc detector_veto no_pii no_pii: AWS Access Key (output 45–65)
Verdict basis Traces
detector_veto 2
clean 1

Unjudged questions: task_completed (3), tool_use_correct (3) — a trace that did not carry what a rule needs.

tests/fixtures/ci-gate/traces.ndjson · 3 evaluated · dataset release-gate: 2 in the gate · exit 1 · what the bases mean

@github-actions

Copy link
Copy Markdown

Iris gate — 1 stored, nothing tripped --fail-on any

iris-eval ingest: 1 stored, 0 tripped --fail-on any

Verdict basis Traces
clean 1

Unjudged questions: task_completed (1), tool_use_correct (1) — a trace that did not carry what a rule needs.

tests/fixtures/ci-gate/clean.ndjson · 1 evaluated · exit 0 · what the bases mean

Red team on the previous commit. The stated reason for dropping Node 20 was
that it is the only supported line with no second storage driver — but a
floor of >=22.0.0 does not make that true. `node:sqlite` arrives in
22.13.0, which is Iris's own NODE_SQLITE_MIN constant, so Node 22.0 through
22.12 have no fallback either. The claim and the number disagreed.

22.13 makes it true: every supported runtime now ships the built-in driver,
so the seam added in 0.15.0 always has something to fall back to when the
native addon will not load.

It also costs nothing. 22.13.0 shipped 2025-01-06 and the current 22.x is
22.23.2 — twenty months and ten minors ago. And it is the number arc 9's
own acceptance matrix recorded as the eventual floor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@irparent
irparent merged commit d23679b into main Sep 22, 2026
26 checks passed
@irparent
irparent deleted the chore/drop-node-20 branch September 22, 2026 16:21

This branch was successfully deployed

1 active deployment
Preview — 95008361 Deployed Sep 22, 2026 by vercel[bot]
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