Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ jobs:
- name: Setup Node.js (for perf comparison)
uses: actions/setup-node@v6
with:
node-version: '22.23.1'
# Single source of truth: .node-version at the repo root. Node here is
# an informational peer (the hard regression gate is perry-vs-perry
# baseline), but keeping it on the same Node the correctness suites
# diff against keeps the published comparison honest. The pin is exact
# for the same reason bun/oha are exact: run-to-run comparability.
node-version-file: .node-version

- name: Setup Bun (for perf comparison)
uses: oven-sh/setup-bun@v2
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/feature-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "26"
# Single source of truth: .node-version at the repo root.
node-version-file: .node-version

- name: Build Perry release binary
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static
Expand Down
24 changes: 22 additions & 2 deletions .github/workflows/node-core-subset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,30 @@ jobs:
shared-key: "${{ runner.os }}-perry"
save-if: ${{ github.ref == 'refs/heads/main' }}

- name: Setup Node.js
# DELIBERATE EXEMPTION from the repo-wide .node-version pin.
#
# This job runs Node's OWN test/parallel corpus, sparse-checked-out at the
# ref in test-compat/node-core/pinned-version.txt. Those tests are written
# against the internals of that exact Node line, so the Node runtime here
# must match the vendored test suite — not the gap-suite oracle. Deriving
# the version from the same file that pins the corpus makes the coupling
# explicit and impossible to break: bump pinned-version.txt and the runtime
# follows. (A bare inline "22" here looked like drift from .node-version;
# it wasn't, and the next person to "fix" it would have broken the job.)
- name: Resolve Node version from the pinned test-corpus ref
id: node_core_version
run: |
set -euo pipefail
# pinned-version.txt holds a git branch name, e.g. "v22.x".
node_ref="$(tr -d '[:space:]' < test-compat/node-core/pinned-version.txt)"
node_version="${node_ref#v}" # v22.x -> 22.x
echo "Pinned Node core corpus: $node_ref -> node-version $node_version"
echo "version=$node_version" >> "$GITHUB_OUTPUT"

- name: Setup Node.js (matches the pinned test corpus, NOT .node-version)
uses: actions/setup-node@v6
with:
node-version: "22"
node-version: ${{ steps.node_core_version.outputs.version }}

- name: Sparse checkout pinned Node.js tests
run: |
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/node-suite-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ jobs:
# wrong reference and produce spurious regressions.
uses: actions/setup-node@v6
with:
node-version: "26"
# Single source of truth: .node-version at the repo root.
node-version-file: .node-version

- name: Build Perry release binary
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/npm-package-sweep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
# Single source of truth: .node-version at the repo root.
node-version-file: .node-version

- name: Build Perry release binary
run: cargo build --release -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release-hono-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
steps:
- uses: actions/checkout@v7

# DELIBERATE EXEMPTION from the repo-wide .node-version pin: this Node is a
# *publishing* toolchain, not a test oracle — it never runs a parity diff.
#
# Node 24 ships npm 11.x. OIDC Trusted Publishing needs npm >= 11.5.1;
# Node 22's npm 10.x silently fails the OIDC handshake and the registry
# returns a misleading 404 on PUT. Do NOT set `registry-url` here — it
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1694,6 +1694,9 @@ jobs:
steps:
- uses: actions/checkout@v7

# DELIBERATE EXEMPTION from the repo-wide .node-version pin: this Node is a
# *publishing* toolchain (npm registry auth), not a test oracle — it never
# runs a parity diff, so the gap suite's Node version is irrelevant here.
- uses: actions/setup-node@v6
with:
node-version: "20"
Expand Down
46 changes: 39 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ jobs:
- name: Setup Node.js for benchmark harness tests
uses: actions/setup-node@v6
with:
node-version: '22.23.1'
# Kept in lockstep with benchmark.yml's peer-comparison Node via the
# shared .node-version pin — these harness tests exercise the same
# comparison scripts that job runs.
node-version-file: .node-version

- name: Validate benchmark artifact and fallback gates
run: |
Expand Down Expand Up @@ -702,11 +705,20 @@ jobs:
# behavioral regressions landed silently between tags (the 2026-06-23
# 851-case test262 regression and the #5763 setPrototypeOf boot breakage
# both shipped through green required checks). This job runs the gap
# suite — every test-files/test_gap_*.ts (258) AOT-compiled and diffed
# suite — every test-files/test_gap_*.ts AOT-compiled and diffed
# byte-for-byte against `node --experimental-strip-types` — and fails on
# any failure NOT already triaged in test-parity/known_failures.json
# (run_gap_tests.sh's no-new-untriaged gate).
#
# THE ORACLE VERSION IS LOAD-BEARING. Node is what we diff against, so a
# test whose feature the pinned Node lacks makes *node* exit non-zero, the
# harness classifies it `node_fail`, and the test is dropped from the gate
# entirely — a silent hole, not a red build. This job sat on Node 22 while
# the suite grew Node 24/26 features, which hid 14 tests (all of Temporal,
# DisposableStack, Float16Array, Uint8Array base64/hex). The pin now lives
# in .node-version so it can't drift out from under the suite again; raise
# it deliberately, and re-measure the delta when you do (see #6364).
#
# Sharded across 8 parallel runners (--shard N/8) so the ~258-test suite
# runs in ~1/8 the wall-time — the 258 sequential Perry compiles dominate
# the cost and split evenly, taking the single-job ~57 min down to ~15 min
Expand Down Expand Up @@ -739,7 +751,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
# Single source of truth: .node-version at the repo root. Node is the
# gap/parity oracle (we byte-diff against it), so the version is a
# correctness input, not an incidental toolchain detail — never pin it
# inline here. See CLAUDE.md ("TypeScript Parity Status").
node-version-file: .node-version

- name: Run gap suite (shard ${{ matrix.shard }}/8)
run: ./scripts/run_gap_tests.sh --shard ${{ matrix.shard }}/8
Expand Down Expand Up @@ -825,7 +841,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
# Single source of truth: .node-version at the repo root. Node is the
# gap/parity oracle (we byte-diff against it), so the version is a
# correctness input, not an incidental toolchain detail — never pin it
# inline here. See CLAUDE.md ("TypeScript Parity Status").
node-version-file: .node-version

- name: Build compiler
run: cargo build --release
Expand Down Expand Up @@ -1399,7 +1419,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
# Single source of truth: .node-version at the repo root. Node is the
# gap/parity oracle (we byte-diff against it), so the version is a
# correctness input, not an incidental toolchain detail — never pin it
# inline here. See CLAUDE.md ("TypeScript Parity Status").
node-version-file: .node-version
Comment on lines +1422 to +1426

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use job-specific rationale for the Node pin.

These package smoke jobs do not run the gap/parity oracle steps in this workflow, but the comments describe Node as that oracle. Keep the single-source-of-truth note, and replace the copied oracle explanation with the fixture-specific reason for pinning Node.

Also applies to: 1488-1492, 1541-1545

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/test.yml around lines 1422 - 1426, Update the comments
accompanying node-version-file in the affected package smoke jobs to retain the
.node-version single-source-of-truth note while replacing the gap/parity-oracle
explanation with the actual fixture-specific rationale for pinning Node. Apply
the same comment correction to all three corresponding job blocks, without
changing the Node configuration.


- name: Install mysql client (for fixture health probe)
run: |
Expand Down Expand Up @@ -1461,7 +1485,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
# Single source of truth: .node-version at the repo root. Node is the
# gap/parity oracle (we byte-diff against it), so the version is a
# correctness input, not an incidental toolchain detail — never pin it
# inline here. See CLAUDE.md ("TypeScript Parity Status").
node-version-file: .node-version

- name: Build perry compiler
run: cargo build --release -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry
Expand Down Expand Up @@ -1510,7 +1538,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
# Single source of truth: .node-version at the repo root. Node is the
# gap/parity oracle (we byte-diff against it), so the version is a
# correctness input, not an incidental toolchain detail — never pin it
# inline here. See CLAUDE.md ("TypeScript Parity Status").
node-version-file: .node-version

- name: Build perry compiler
run: cargo build --release -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry
Expand Down
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
26.5.0
6 changes: 5 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ Perry is a native TypeScript compiler written in Rust that compiles TypeScript s

## TypeScript Parity Status

Tracked via the gap test suite (`test-files/test_gap_*.ts`, 258 tests). Compared byte-for-byte against `node --experimental-strip-types`. Run via `./scripts/run_gap_tests.sh` (a thin wrapper over `run_parity_tests.sh --filter test_gap_` that builds the compiler itself and gates on no new untriaged failures).
Tracked via the gap test suite (`test-files/test_gap_*.ts`). Compared byte-for-byte against `node --experimental-strip-types`. Run via `./scripts/run_gap_tests.sh` (a thin wrapper over `run_parity_tests.sh --filter test_gap_` that builds the compiler itself and gates on no new untriaged failures).

**The oracle is Node `26.5.0`, pinned in `.node-version` at the repo root** — the single source of truth every CI workflow reads via `setup-node`'s `node-version-file`. **Run the gap suite against that exact version locally**, or your results won't match CI. The version is a *correctness input*, not an incidental toolchain detail: when node can't run a test (a feature newer than the pinned node), node exits non-zero, the harness classifies it `node_fail`, and the test is **silently dropped from the gate** rather than going red. CI sat on Node 22 while the suite grew Node 24/26 features, which hid 14 tests — all of Temporal, plus DisposableStack, Float16Array, and `Uint8Array` base64/hex (#6364). Node patch releases also change observable output (error-message text, `v8` heap fields), which is why the pin is exact. Raising it is a deliberate act: measure the failure delta under both oracles first, then triage what it exposes.

Two workflows are deliberately exempt and say so inline: `node-core-subset.yml` derives its Node from `test-compat/node-core/pinned-version.txt` (it runs Node's *own* test corpus, which must match its own Node line), and the two release workflows use Node purely as an npm *publishing* toolchain.

**Last full sweep:** run `./run_parity_tests.sh` for the current snapshot. The umbrella tracker is #793 (Node.js + TypeScript compatibility roadmap); the previously-cited #447–#452 batch closed on 2026-05-04. Currently-open trackers worth knowing about:

Expand Down
6 changes: 6 additions & 0 deletions test-parity/known_failures.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,11 @@
"added": "2026-07-04",
"category": "module-inventory",
"reason": "node:readline surface (#3698+) \u2014 compile_fail in the 2026-07-03 baseline (tls/zlib/readline compile cluster, possibly runner env); standing per #5917."
},
"test_gap_disposablestack_2875": {
"issue": "6364",
"added": "2026-07-13",
"category": "bug-open",
"reason": "DisposableStack/Symbol.dispose surface incomplete: `.disposed` returns undefined where Node returns false/true, and the dispose path leaves the adopt/defer callback count at 0. NEWLY VISIBLE, not a regression: DisposableStack is Node 24+, so under CI's old Node 22 pin *node itself* exited non-zero, the harness classified the test `node_fail`, and it was dropped from the gate entirely. Raising the oracle to 26 (.node-version) makes the pre-existing gap observable for the first time. Perry's implementation lives in crates/perry-runtime/src/disposable.rs. Flips to PASS when #6364 lands."
}
}
Loading