Skip to content

ci(plugin-ci): default to the Node plugins actually run on (20 → 24) - #35

Merged
ken-jo merged 1 commit into
mainfrom
chore/plugin-ci-node-24
Aug 27, 2026
Merged

ci(plugin-ci): default to the Node plugins actually run on (20 → 24)#35
ken-jo merged 1 commit into
mainfrom
chore/plugin-ci-node-24

Conversation

@ken-jo

@ken-jo ken-jo commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What

plugin-ci.yml node-version default: '20''24'. One line, plus the comment recording why the number is what it is.

No plugin repo overrides this input, so this moves all 7 at once — which is exactly why it was proven on one repo first.

Why '20' was wrong on two independent axes

It is end-of-life. Per nodejs/Release/schedule.json, v20 maintenance ended 2026-04-30. Four months of plugin CI has run on an unsupported runtime.

It was never the right number. The host spawns out-of-process plugins as process.execPath — the Electron binary — under ELECTRON_RUN_AS_NODE=1 (lvis-app/src/plugins/isolation/out-of-process-plugin.ts). A plugin's Node is Electron's bundled Node. Measured on the host's Electron 43 rather than read off a table:

$ ELECTRON_RUN_AS_NODE=1 electron -e 'console.log("electron="+process.versions.electron,"node="+process.versions.node)'
electron=43.0.0 node=24.17.0

So CI was testing four majors below production. A green suite on 20 could not answer whether the plugin works where it runs.

This already cost real work

lvis-plugin-ep Dependabot #194 (jsdom 29 → 30) fails CI with TypeError: webidl.util.markAsUncloneable is not a function. jsdom 30 → undici 8 → worker_threads.markAsUncloneable, added in Node 22. Production has it. Only CI did not — the bump passed locally on Node 26 the whole time. A dependency was blocked by the test environment rather than by the code, and the red check was describing a runtime no user has.

Proof before the flip

lvis-project/lvis-plugin-ep#226 pinned node-version: '24' for one repo and changed nothing else, so its result is evidence about the Node and not about anything bundled with it:

  • ci / build-test pass, 41s, same self-hosted runner
  • Log confirms the version was applied, not silently ignored: Acquiring 24.19.0 - arm64 …node: v24.19.0

That last check matters: a with: block that gets ignored produces a green run too. The number had to be read back out of the run.

After this merges

  1. Dispatch CI on each plugin repo's main and confirm all 7 are green on Node 24.
  2. Close ep#226 — once the default is '24' the override merely restates it, and an override that restates the default is how a stale pin outlives its reason.
  3. Unblock ep#194 (jsdom 30).

Maintenance

The comment ties the number to the host's Electron, not to "latest LTS". When lvis-app moves Electron majors, re-read Electron's bundled Node and move this with it.

Node 20 reached end-of-life on 2026-04-30. No plugin repo overrides
`node-version`, so all seven have been testing on an unsupported runtime for
four months.

Worse, 20 was never the right number. The host spawns out-of-process plugins
as `process.execPath` -- the Electron binary -- under ELECTRON_RUN_AS_NODE=1,
so a plugin's Node IS Electron's bundled Node. Measured directly on the host's
Electron 43: node 24.17.0. CI was testing four majors below production, which
means a green suite could not answer the question anyone actually has.

The gap had already blocked work: jsdom 30 pulls undici 8, which calls
`worker_threads.markAsUncloneable` (Node 22+). Production has it; only CI did
not, so lvis-plugin-ep's Dependabot bump failed on a runtime no user runs.

Proven before flipping: lvis-plugin-ep#226 pinned node-version: '24' for one
repo and changed nothing else. The run installed v24.19.0 and the full suite
passed in 41s on the same self-hosted runner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EbNct32BA3E96EER8Y1eE
@ken-jo
ken-jo merged commit a840c98 into main Aug 27, 2026
1 check passed
@ken-jo
ken-jo deleted the chore/plugin-ci-node-24 branch August 27, 2026 01:49
@ken-jo

ken-jo commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Correction to the PR body: this moves 6 repos, not 7.

lvis-plugin-sdk does not call plugin-ci.yml at all — it is public, so it runs its own test.yml on GitHub-hosted runners and never touches the self-hosted group. The six that do inherit this default are meeting, ms-graph, ep, work-assistant, local-indexer, and template (verified by grepping each repo's ci.yml for plugin-ci.yml@main: 1 hit each, 0 for the SDK).

Worth recording how the wrong number got in: my first sweep queried .github/workflows/ci.yml in each repo and printed the node-version hits. For the SDK that request 404'd — no such file — and the empty result rendered identically to "exists, no override." A missing measurement read as a clean one. The SDK's Node version is a separate question with a separate answer, and this PR does not touch it.

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