Skip to content

ci: Node 22/24 test workflow; better-sqlite3 13 to stop the Node 24.19 ObjectWrap abort - #9

Merged
Freshair129 merged 1 commit into
mainfrom
ci/node-test-workflow
Sep 11, 2026
Merged

Freshair129 merged 1 commit into
mainfrom
ci/node-test-workflow

Conversation

@Freshair129

Copy link
Copy Markdown
Owner

Summary

Two infrastructure fixes, no pipeline logic touched (packages/gks-core/src/pipeline.mjs is untouched; PR #7 owns it).

  1. CI (GKS had none). .github/workflows/test.yml runs npm ci + npm test (vitest contract + integration, then the node:test security suite) on ubuntu-latest, Node 22 and 24 matrix, on pull_request and push to main. actions/checkout v7.0.1 and actions/setup-node v7.0.0 (npm cache) are pinned to commit SHAs; permissions: contents: read; no secrets. The external MSP integration suite skips without MSP_REPO_ROOT, as intended.
  2. Node 24.19 SQLite abort. better-sqlite3 ^11.10.0^13.0.3; root engines.node >=20>=22 (13's floor).

Root cause of the abort

node::RemoveEnvironmentCleanupHook ... Assertion failed: (env) != nullptr under Statement::~Statement is an upstream Node.js regression. It is not caused by how GKS caches or closes statements:

  • Node 24.19.0 backported src: add cleanup hooks to node::ObjectWrap (nodejs/node#63642) into the header-only node_object_wrap.h: the constructor adds a cleanup hook, and ~ObjectWrap() calls RemoveEnvironmentCleanupHook(Isolate::GetCurrent(), …). It did not backport the global addon cleanup-hook registry (1723773d), which is what makes removal safe without a live Environment. So when V8 collects a wrapped object with no entered context (allocation-driven GC, weak callback), Environment::GetCurrent is null and the CHECK aborts. Tracked as nodejs/node#65446. The v24 backport of the registry is still open (nodejs/node#65943). I checked the tags: v24.20.0 and v24.21.0 still have the new header and no CleanupHookThunk in src/api/hooks.cc, so upgrading Node does not fix it yet.
  • The code only lands in an addon that is compiled against 24.19+ headers. better-sqlite3 11.10.0 publishes no node-v137 prebuild, so npm ci on Node 24 builds it from source against those headers. Any Statement collected by GC can then abort the process, including mid-run with the Database still open. The "statement outlives db.close()" hypothesis does not hold: GC of any statement can trigger it.
  • Binary evidence on this machine: the 11.10.0 source build imports RemoveEnvironmentCleanupHook. The 12.11.1 prebuild (built before 24.19) imports only AddEnvironmentCleanupHook. The 13.0.3 prebuild imports neither and uses napi_wrap.
  • better-sqlite3 13.0.0 is a node-addon-api rewrite (Statement : Napi::ObjectWrap<Statement>) that ships its prebuilt binaries inside the package (release notes), so it is structurally outside the broken header. For reference, the upstream report WiseLibs/better-sqlite3#1515 was closed as not planned, pointing at the Node regression.
  • 12.11.1 would also pass today, but only because its prebuild predates 24.19; any source build of it would re-arm the abort. So 13 is the durable choice. API usage is unchanged, and the full suite passes on 13 without code edits.

Verification (this machine: Windows 11, Node v24.19.0)

pipeline-genesisrag17.test.mjs (vitest) security suite (node:test)
before, better-sqlite3 11.10.0 (source build) Assertion failed: (env) != nullptr, worker exited unexpectedly abort, file fails, tests 1 / pass 0 / fail 1
after, better-sqlite3 13.0.3 16 / 16 passed 10 / 10 passed

Full npm test after a clean npm ci: vitest 19 files passed | 2 skipped (21), 156 tests passed | 2 skipped (158); node:test security 10 pass, 0 fail. The 2 skips are the external MSP tests (msp-provider-compatibility, msp-service-chain), which skip because MSP_REPO_ROOT is unset.

Docs

No DPS-KI-* stage is advanced by this PR. It is test and CI infrastructure only.

🤖 Generated with Claude Code

…o stop the Node 24.19 ObjectWrap abort

GKS had no CI. .github/workflows/test.yml runs `npm ci` + `npm test`
(vitest contract+integration, node:test security) on ubuntu-latest with
Node 22 and 24, on pull_request and push to main. Actions are pinned to
commit SHAs (checkout v7.0.1, setup-node v7.0.0 with npm cache); no
secrets; the external MSP suite skips without MSP_REPO_ROOT.

SQLite-backed tests aborted the process on Node 24.19.0 with
`node::RemoveEnvironmentCleanupHook ... Assertion failed: (env) != nullptr`
under `Statement::~Statement`. Root cause is upstream, not GKS's statement
handling: Node 24.19.0 backported "src: add cleanup hooks to
node::ObjectWrap" (nodejs/node#63642) into the header-only
node_object_wrap.h without the global cleanup-hook registry (1723773d),
so ~ObjectWrap() calls RemoveEnvironmentCleanupHook(Isolate::GetCurrent())
and aborts whenever a wrapped object is collected with no entered
context (nodejs/node#65446; v24 backport of the registry still open in
nodejs/node#65943; 24.20.0 and 24.21.0 are unchanged). better-sqlite3
11.10.0 has no node-v137 prebuild, so it was compiled from source
against the 24.19.0 headers and inherited the new destructor; any
Statement GC could abort, whether or not its Database was closed.

better-sqlite3 13 is a node-addon-api rewrite (Napi::ObjectWrap, napi_wrap)
with prebuilt binaries shipped in the package; its binary imports neither
cleanup-hook symbol. Node floor raised to >=22 to match it.

Local (Windows, Node 24.19.0): before, pipeline-genesisrag17 aborts
(worker exited unexpectedly) and the security file fails 0/1; after,
npm test = vitest 19 files passed | 2 skipped, 156 tests passed |
2 skipped; node:test security 10/10 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Freshair129
Freshair129 merged commit 36d8acc into main Sep 11, 2026
2 checks passed
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