Skip to content

ci: gate coverage, test on Node 26, and run the pack test on Node 20.19 - #184

Merged
dgesteves merged 1 commit into
mainfrom
fix/os2-55-ci-gates
Oct 16, 2026
Merged

dgesteves merged 1 commit into
mainfrom
fix/os2-55-ci-gates

Conversation

@dgesteves

@dgesteves dgesteves commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Roadmap item: OS2-55 (findings os-ci-release/no-coverage-gate and os-ci-release/node-matrix).

What was wrong

  • Coverage was neither measured nor enforced: no coverage provider in devDependencies, no coverage block in vitest.config.ts, and nothing in .github/ (git grep -n coverage package.json vitest.config.ts .github/ matched nothing on main 5c6277f).
  • CI tested on Node 22 and 24 only. Node 26 becomes LTS on 2026-10-28.
  • The Node 20.19 job ran the smoke test and one check, but not the pack test, although package.json declares node >=20.19.

What changed

  • @vitest/coverage-istanbul 5.0.3, the same version as vitest. It uses the same ^5.0.3 range, so Dependabot's dev-dependencies group moves them together. pnpm test:coverage runs vitest run --coverage.
  • vitest.config.ts: a coverage block with the Istanbul provider over src/** and action/**, the text and json-summary reporters, and thresholds at today's level rounded down: lines 94, branches 84, functions 93, statements 91. pnpm test doesn't measure coverage, so it is as fast as before.
  • ci.yml:
    • A new Coverage job (Ubuntu, Node 24) runs pnpm test:coverage, then writes the totals to the job summary. The summary step runs even when a threshold fails (if: ${{ !cancelled() }}), and says there is no report when the tests failed first. The other test jobs still run pnpm test.
    • The test matrix is now node: [22, 24, 26]. setup-node installed v26.12.0.
    • The Node 20.19 job (renamed "Built CLI and pack test on Node 20.19") now also runs node scripts/pack-test.mjs and node scripts/pack-test-eslint8.mjs after switching to 20.19 (v20.19.6 on CI). They run with node, not pnpm pack-test, because pnpm 11.6.0 needs Node >=22.13.

Where this differs from the findings' proposal

  • Istanbul instead of v8. The first push of this PR used @vitest/coverage-v8, as proposed. On CI its Coverage job took 9m35s, against 2m26s for Test (Node 24) in the same run, and it failed on a 30 s test timeout (test/workspace.test.ts, "records one baseline at the root…"). v8 counts every block V8 runs, the TypeScript compiler's included, so the tests that build a TypeScript program slowed down most: on CI, test/cli.test.ts went from 31.8 s to 182.1 s, test/workspace.test.ts from 13.3 s to 83.7 s and test/baseline.test.ts from 12.9 s to 79.8 s. Istanbul instruments only src/ and action/. Locally, with 4 workers like a CI runner, the suite took 41.6 s without coverage, 72.0 s with Istanbul and 185.6 s with v8 (machine load between 7 and 20). For test/cli.test.ts alone: 11.9 s, 12.6 s and 95.6 s. Both providers give the same statements, functions and lines. They differ on branches (84.89% with Istanbul, 85.37% with v8), so the branch threshold is 84.
  • Thresholds. The verifier proposed lines 93 and branches 83 (measured at 6004f1e). Main has moved since, so I measured again and used those numbers rounded down (table below).
  • Smoke test and check kept. The finding proposed running the pack test "instead of smoke plus check" on 20.19. I kept both. The smoke test calls every tool over stdio, which the pack test doesn't. On CI, the smoke test took 6 s and the check 2 s.

Coverage today

pnpm test:coverage Statements Branches Functions Lines
This PR's CI (merged with main 5be17ed), all files 92.03 84.99 93.71 94.52
src/ 94.53 85.88 95.05 96.19
action/ 91.51 82.83 88 94.28
Local (on 5c6277f), all files 91.87 84.89 93.55 94.39
Thresholds 91 84 93 94

CI minutes

From this PR's run 38883460129, as runner time per CI run:

  • Coverage: 219 s (new job).
  • Test (Node 26): 195 s (new matrix entry).
  • Node 20.19 job: 70 s. It took 44 s and 36 s in the last two main runs. The two pack test steps take 13 s and 10 s.

That adds about 7.4 minutes of runner time per run (about 9 minutes billed with per-job rounding). Wall-clock time stays the same: Coverage (3m39s) finishes before the Windows and macOS test jobs (4m48s and 4m32s) and the corpus job (7m33s).

How it was tested

  • New test/ci-gates.test.ts (9 tests). On main, all 9 fail. On this branch, all 9 pass. It checks:
    • the coverage config: Istanbul, src/** and action/**, off unless asked for, json-summary, and all four thresholds;
    • that the provider matches the vitest range and the installed vitest version;
    • that only the coverage job measures coverage, on Ubuntu and Node 24, and that test and os still run pnpm test;
    • that the summary step runs after pnpm test:coverage and also when a threshold fails;
    • running the summary step's script in bash: once with a json-summary (the table) and once without one (the note);
    • the Node 22/24/26 matrix;
    • that the Node 20.19 job builds on 24, runs no pnpm after switching, and runs both scripts of pnpm pack-test in order.
  • Gate (local): pnpm install --frozen-lockfile --prefer-offline, pnpm format:check, pnpm lint, pnpm typecheck, pnpm test (1023 passed, 3 skipped, 30.0 s) and pnpm build (no change to schema.json) all pass. pnpm test:coverage exits 0 (34.6 s).
  • A failing threshold: vitest run --coverage test/sarif.test.ts exits 1 with ERROR: Coverage for lines (35.58%) does not meet global threshold (94%), and still writes coverage/coverage-summary.json. The summary step's script, run on that file, printed the table.
  • CI on this PR: every job passes. Test (Node 26) passed 1051 tests and skipped 3 on v26.12.0. The Node 20.19 job printed "pack test passed" and "pack test on ESLint 8 passed" on v20.19.6.
  • Locally, the suite on Node 26.3.0 (1023 passed, 3 skipped). The 20.19 job's steps on Node 20.20.1, the closest version installed here, after pnpm build on 24: all exit 0.

Not in this PR

  • CONTRIBUTING.md line 24 still says the tests run "on Node 22 and 24 (Linux)", and doesn't mention pnpm test:coverage. X2-28 edits CONTRIBUTING.md in the same wave, so this line is a follow-up after X2-28 merges: "on Node 22, 24 and 26 (Linux)", plus a pnpm test:coverage line.
  • The required checks on main are still "Lint, typecheck, build", "Test (Node 22)" and "Test (Node 24)". Making "Coverage" or "Test (Node 26)" required is a ruleset change for the owner.
  • pnpm-lock.yaml changes for the new dev dependency. No other wave 3 onsystem item lists the lockfile.
  • The thresholds don't rise on their own. Raise them by hand when coverage goes up.

Coverage of src/ and action/ was neither measured nor enforced. pnpm
test:coverage now measures it with @vitest/coverage-istanbul, with
thresholds at today's level rounded down (lines 94, branches 84,
functions 93, statements 91), in one CI job on Node 24 that also writes
the totals to the job summary. pnpm test and the other test jobs run
without it. Istanbul rather than v8: v8 counts every block V8 runs,
the TypeScript compiler's included, and made the tests that build a
program about six times slower on CI, past the 30 s test timeout.

The test matrix adds Node 26, which becomes LTS on 2026-10-28. The
Node 20.19 job, which ran only the smoke test and one check, now also
runs both pack test scripts there, with node, since pnpm needs a newer
Node.
@dgesteves
dgesteves force-pushed the fix/os2-55-ci-gates branch from 3a96a52 to ff968c0 Compare October 16, 2026 09:52
@dgesteves
dgesteves merged commit ecabf64 into main Oct 16, 2026
15 checks passed
@dgesteves
dgesteves deleted the fix/os2-55-ci-gates branch October 16, 2026 10:32
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