You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Deferred from #1984 (10.0.10 release prep) by decision: 10.0.10 ships the declaration plus a documented Known-issue; enforcement lands in 10.0.11.
Background
10.0.10 makes node:sqlite a hard startup dependency. prepareRfc64PersistenceV1() is awaited in DKGAgent.start()outside the surrounding try/catch, and the CLI daemon always passes a dataDir, so on an unsupported runtime the node does not boot.
Supported range (declared in 10.0.10 on @origintrail-official/dkg and @origintrail-official/dkg-agent):
>=22.13.0 <23.0.0 || >=23.4.0
node:sqlite ships from Node 22.5.0 but stays behind --experimental-sqlite until 22.13.0 / 23.4.0, and the daemon builds its command from process.execArgv and never passes that flag.
Why engines is not enough (verified, not assumed)
pnpm install --frozen-lockfile with an impossible engines.node: WARN Unsupported engine, install completes, exit 0. With --config.engine-strict=true: ERR_PNPM_UNSUPPORTED_ENGINE, exit 1.
npm install --production --no-audit --no-fund (the exact form the npm-slot updater runs): npm warn EBADENGINE, exit 0. With --engine-strict: exit 1.
pnpm config get engine-strict in this repo → unset (default false). The repo .npmrc does not set it.
The gap that actually strands a fleet
Blue-green auto-update gates activation on existsSync of build output only — nothing launches the new slot to prove it boots:
git path: build-output checks at packages/cli/src/daemon/auto-update.ts:1407-1418, then swapSlot(target) at :1496
npm-slot path: checks at :578-598, then swapSlot(target) at :656
So a node auto-updating onto 10.0.10 on Node 22.12 installs cleanly, passes every existing check, activates the slot, and then restart-loops — with a message the operator never sees, because dkg start detaches the daemon with stdio: ['ignore','ignore','ignore'] (packages/cli/src/commands/lifecycle.ts:194-203).
dkg update does run a preflight (UPDATE_PREFLIGHT_CHECKS = ['install-layout','version-skew'], packages/cli/src/doctor/index.ts:46), but the unattended auto-update-runner.ts never imports doctor, so scheduled updates have no preflight at all.
Proposed work
Probe capability, not the version string. Use process.getBuiltinModule('node:sqlite') (guard typeof process.getBuiltinModule === 'function'; added v22.3.0) rather than comparing process.version. A capability probe also catches a --without-sqlite custom build and correctly passes someone running 22.10 with --experimental-sqlite. The error message should name the supported range and the current process.version.
New minimal module (no heavy imports), e.g. packages/cli/src/node-runtime-preflight.ts.
Wire before the existing configExists() guard at packages/cli/src/commands/lifecycle.ts:136 — the only surface where the message reaches an operator's terminal.
Wire in the daemon near exitOnStoreConfigErrors (packages/cli/src/daemon/lifecycle.ts:~1400), well before DKGAgent.create at :1699, so --foreground and supervisor respawns log a readable reason.
Extend the shared throw at packages/agent/src/sqlite/module-loader-v1.ts:8 to name the version floor — it is the common site for all consumers (rfc64/inventory-v1/open.ts:603, finalization-recovery-sqlite-schema.ts:258, generic-sql-source.ts:698), so fixing it there sweeps the class.
Add a node-runtime doctor check (packages/cli/src/doctor/), include it in ALL_CHECK_IDSandUPDATE_PREFLIGHT_CHECKS, and add a runtime block to StateSummary.
Gate before swapSlot on both auto-update paths (auto-update.ts:1496 and :656) so unattended updates cannot activate an unbootable slot.
Release-metadata guard: assert in scripts/release-packages.mjs that every publishable package importing node:sqlite declares the supported range, so the contract cannot drift as new packages adopt it. (Raised as a 🟡 on chore(release): bump version set to 10.0.10 #1984.)
Optional hardening: --engine-strict on the npm-slot install (auto-update.ts:558) and engine-strict=true in .npmrc — the latter does bite the git-slot path, since auto-update.ts:1306 runs pnpm with cwd set to a checkout containing .npmrc.
Do not hang the check on the packages/clipostinstall: it is skipped by --ignore-scripts, its best-effort contract forbids failing an install, and it never runs on the git-slot path.
Docs to update alongside
README.md:70 and docs/getting-started/quickstart.md:24 both say "Node.js 22+", which is now under-specified.
Acceptance
Node 22.12 (and 23.2) cannot be promoted or started as 10.0.10+; the failure is loud, early, and names the required range.
Node 22.13+ / 23.4+ / 24+ installs and starts unchanged.
A node auto-updating on an unsupported runtime refuses to activate the slot instead of activating and restart-looping.
Deferred from #1984 (10.0.10 release prep) by decision: 10.0.10 ships the declaration plus a documented Known-issue; enforcement lands in 10.0.11.
Background
10.0.10 makes
node:sqlitea hard startup dependency.prepareRfc64PersistenceV1()is awaited inDKGAgent.start()outside the surrounding try/catch, and the CLI daemon always passes adataDir, so on an unsupported runtime the node does not boot.Supported range (declared in 10.0.10 on
@origintrail-official/dkgand@origintrail-official/dkg-agent):node:sqliteships from Node 22.5.0 but stays behind--experimental-sqliteuntil 22.13.0 / 23.4.0, and the daemon builds its command fromprocess.execArgvand never passes that flag.Why
enginesis not enough (verified, not assumed)pnpm install --frozen-lockfilewith an impossibleengines.node:WARN Unsupported engine, install completes, exit 0. With--config.engine-strict=true:ERR_PNPM_UNSUPPORTED_ENGINE, exit 1.npm install --production --no-audit --no-fund(the exact form the npm-slot updater runs):npm warn EBADENGINE, exit 0. With--engine-strict: exit 1.pnpm config get engine-strictin this repo → unset (defaultfalse). The repo.npmrcdoes not set it.The gap that actually strands a fleet
Blue-green auto-update gates activation on
existsSyncof build output only — nothing launches the new slot to prove it boots:packages/cli/src/daemon/auto-update.ts:1407-1418, thenswapSlot(target)at:1496:578-598, thenswapSlot(target)at:656swapSlotitself:packages/cli/src/config.ts:1812-1830So a node auto-updating onto 10.0.10 on Node 22.12 installs cleanly, passes every existing check, activates the slot, and then restart-loops — with a message the operator never sees, because
dkg startdetaches the daemon withstdio: ['ignore','ignore','ignore'](packages/cli/src/commands/lifecycle.ts:194-203).dkg updatedoes run a preflight (UPDATE_PREFLIGHT_CHECKS = ['install-layout','version-skew'],packages/cli/src/doctor/index.ts:46), but the unattendedauto-update-runner.tsnever imports doctor, so scheduled updates have no preflight at all.Proposed work
Probe capability, not the version string. Use
process.getBuiltinModule('node:sqlite')(guardtypeof process.getBuiltinModule === 'function'; added v22.3.0) rather than comparingprocess.version. A capability probe also catches a--without-sqlitecustom build and correctly passes someone running 22.10 with--experimental-sqlite. The error message should name the supported range and the currentprocess.version.packages/cli/src/node-runtime-preflight.ts.configExists()guard atpackages/cli/src/commands/lifecycle.ts:136— the only surface where the message reaches an operator's terminal.exitOnStoreConfigErrors(packages/cli/src/daemon/lifecycle.ts:~1400), well beforeDKGAgent.createat:1699, so--foregroundand supervisor respawns log a readable reason.packages/agent/src/sqlite/module-loader-v1.ts:8to name the version floor — it is the common site for all consumers (rfc64/inventory-v1/open.ts:603,finalization-recovery-sqlite-schema.ts:258,generic-sql-source.ts:698), so fixing it there sweeps the class.node-runtimedoctor check (packages/cli/src/doctor/), include it inALL_CHECK_IDSandUPDATE_PREFLIGHT_CHECKS, and add aruntimeblock toStateSummary.swapSloton both auto-update paths (auto-update.ts:1496and:656) so unattended updates cannot activate an unbootable slot.scripts/release-packages.mjsthat every publishable package importingnode:sqlitedeclares the supported range, so the contract cannot drift as new packages adopt it. (Raised as a 🟡 on chore(release): bump version set to 10.0.10 #1984.)Optional hardening:
--engine-stricton the npm-slot install (auto-update.ts:558) andengine-strict=truein.npmrc— the latter does bite the git-slot path, sinceauto-update.ts:1306runs pnpm withcwdset to a checkout containing.npmrc.Do not hang the check on the
packages/clipostinstall: it is skipped by--ignore-scripts, its best-effort contract forbids failing an install, and it never runs on the git-slot path.Docs to update alongside
README.md:70anddocs/getting-started/quickstart.md:24both say "Node.js 22+", which is now under-specified.Acceptance