Skip to content

S0251-cli-runtime-1: declare a Node range the CI matrix actually exercises - #54

Open
NSchatz wants to merge 1 commit into
mainfrom
sdd/S0251-cli-runtime-1
Open

S0251-cli-runtime-1: declare a Node range the CI matrix actually exercises#54
NSchatz wants to merge 1 commit into
mainfrom
sdd/S0251-cli-runtime-1

Conversation

@NSchatz

@NSchatz NSchatz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Spec: work/specs/S0251-cli-runtime-1/spec.md (umbrella).

The gap

engines.node declared >=22.0.0. The test matrix runs 22 and 24. Node 26 is
supported upstream, was admitted by that range, and was exercised by nothing, so
an install on Node 26 was a combination nobody here had run and the manifest said
nothing about it.

The direction, and why it is not symmetric

The claim narrows; the matrix does not grow. Each matrix cell emits a required
status-check context (ci / verify (22, ubuntu-latest), ci / verify (24, ubuntu-latest)) named in the ci-required-checks ruleset with bypass_actors: [], and no commit in any repository can edit that ruleset.

  • A cell added without its context arrives NOT REQUIRED: a red X that blocks
    nothing. That has happened here for real once (prepublish, 2026-08-05).
  • A cell removed leaves a required context nothing emits, which is PENDING
    rather than failing, and leaves every pull request unmergeable by anyone,
    admin included, including the one that would undo it.

So widening is a three-step change that starts outside this repository: ruleset
first, matrix second, range third. This PR does none of it.

No status-check name changes here. The caller passes the same two values the
shared workflow already defaults to, so the runs and every context name are
byte-identical to the run before this change.

What changed

  • package.json: engines.node becomes >=22.0.0 <26.0.0. The minimal
    narrowing that excludes the offending line and nothing more, because a
    published range is corrected only by another publish, never by a retraction.
  • .github/workflows/ci.yml: passes node-versions: '["22", "24"]'
    explicitly, so the tested set is a fact stated in this repository rather than
    an input default resolved in another one. The comment records why the values
    are not free to change.
  • test/node-release-schedule.json: the upstream nodejs/Release schedule,
    with its source URL, accessed date and sha256 recorded beside it, so support is
    derived from a primary record rather than a number typed into a test.
  • test/node-support.test.ts: the guard.
  • CLAUDE.md and docs-content/installation.md: state the bound too, so
    no surface still promises a runtime the suite never runs.

What the guard does

It derives the supported set at the run date (start <= today < end) from the
committed record, and reds on:

  • a supported major the range admits but the matrix does not exercise (the
    message names the major, the range and the matrix);
  • a matrix cell the range does not admit, which is how a narrowed range silently
    strands a tested line;
  • a range admitting a major the record does not carry, which is unknown rather
    than unsupported;
  • a range with no upper bound;
  • the contributor guide or the installation page restating either one
    differently.

It refuses to report agreement over an absent, empty or provenance-less record,
and asserts it opened a real one first. Every failure direction is proved over a
constructed input at an injected run date, and the LTS-to-Maintenance transition
(v24, 2026-10-20) is proved not to change anything while an end date is proved
to stop requiring a line in the matrix.

The guard was watched failing against the pre-change tree: reverting engines
to >=22.0.0 reports range-unbounded-above and range-admits-untested-major
naming Node 26, the range and the matrix.

Out of scope, deliberately

No src/ change: no runtime version check, no startup diagnostic, no exit code.
Nothing in cosyte/.github is edited. The ci-required-checks ruleset is
untouched. The uses: ...@main reference is left alone (a real finding, a
separate item). fuzz.yml and release.yml keep their own node-version: 22
pins. Nothing asserts how a package manager reacts to an engines mismatch.

…cises

`engines.node` said `>=22.0.0` while the test matrix ran 22 and 24 only. Node
26 is supported upstream, sat inside that range, and was exercised by nothing,
so an install on Node 26 was a combination nobody here had run and the manifest
said nothing about it.

The claim narrows to the tested set rather than the tested set widening to the
claim. Each matrix cell emits a required status-check context named in a GitHub
ruleset with no bypass actors, and no commit in this repository can edit it: a
cell added without its context arrives NOT REQUIRED (a red X that blocks
nothing) and a cell removed leaves a required context nothing emits, which
makes every pull request unmergeable by anyone. Widening starts outside this
repository: ruleset first, matrix second, range third.

- `engines.node` becomes `>=22.0.0 <26.0.0`: the minimal narrowing that
  excludes the offending line and nothing more, since a published range is
  corrected only by another publish.
- `.github/workflows/ci.yml` passes `node-versions: '["22", "24"]'`
  explicitly. Same two values the shared workflow already defaults to, so the
  runs and every context name are unchanged; what changes is that the tested
  set is a fact stated in this repository rather than an input default resolved
  in another one.
- `test/node-release-schedule.json` carries the upstream release schedule with
  its source URL, accessed date and sha256, so the guard derives support from a
  primary record instead of a number typed into a test.
- `test/node-support.test.ts` reds when the range and the matrix disagree in
  either direction, when the range admits a major the schedule does not carry,
  when the range has no upper bound, and when the contributor guide or the
  installation page restates either one differently. It refuses to report
  agreement over an absent, empty or provenance-less record, and every failure
  direction is proved over a constructed input at an injected run date.
- `CLAUDE.md` and `docs-content/installation.md` state the bound too, so no
  surface still promises a runtime the suite never runs.

No `src/` change: no runtime version check, no startup diagnostic, no new exit
code. `fuzz.yml` and `release.yml` keep their own `node-version: 22` pins.
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