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
90 changes: 90 additions & 0 deletions .github/workflows/node-compat-matrix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Node Compat Matrix Guard

# Gates scripts/node_compat_matrix.mjs --check: a breadth sweep over every
# require("module").builtinModules entry, both import forms (M and node:M),
# against a PINNED, SRI-verified Node oracle (external-tools.json tools.node,
# currently 26.5.1). It compares Perry's export-SHAPE fingerprint per module
# to the oracle's and FAILS if any baselined cell got strictly worse or a
# prefix-parity invariant broke (test-parity/node-compat-matrix.baseline.json).
# The systematic form of tracker #812. Behavioral parity stays in the
# node-suite (node-suite-guard.yml) — this is shape breadth, one pinned oracle.
#
# Its OWN job on purpose: the runner downloads the pinned Node dist tarball
# (~40MB) and verifies it, which must not slow the main cargo-test job. The
# node used by setup-node here only EXECUTES the .mjs; the oracle Node is the
# pinned dist the runner fetches + SRI-verifies itself.
#
# Decoupled from the (not-yet-enabled) merge queue like node-suite-guard.yml:
# runs nightly + on demand today, and the merge_group trigger is INERT until a
# maintainer enables the merge queue in branch protection.
on:
workflow_dispatch:
schedule:
# Nightly, offset from node-suite-guard (37 4) and the Core Subset Radar
# (17 3) to avoid overlap.
- cron: "57 4 * * *"
merge_group:

permissions:
contents: read

concurrency:
group: node-compat-matrix-${{ github.ref }}
cancel-in-progress: false

env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
SCCACHE_CACHE_SIZE: "2G"
CARGO_INCREMENTAL: "0"

jobs:
node-compat-matrix:
# macOS arm64 to MATCH the committed darwin-arm64 baseline
# (test-parity/node-compat-matrix.baseline.json). The gate now refuses a
# cross-platform comparison outright (checkAgainstBaseline rejects a
# platform/nodeVersion mismatch), so a darwin baseline must be gated on a
# darwin-arm64 runner — an ubuntu (linux-x64) runner would fail the scope
# guard rather than silently compare platform-dependent fingerprints.
runs-on: macos-14
timeout-minutes: 120
Comment thread
coderabbitai[bot] marked this conversation as resolved.
steps:
- uses: actions/checkout@v7
with:
# Read-only job (build + verify); don't leave the GITHUB_TOKEN in
# the local git config (least privilege — OWASP / CodeRabbit).
persist-credentials: false

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Start sccache
uses: mozilla-actions/sccache-action@v0.0.10

- uses: Swatinem/rust-cache@v2
with:
shared-key: "${{ runner.os }}-perry"
save-if: ${{ github.ref == 'refs/heads/main' }}

- name: Setup Node.js (executes the runner; oracle is the pinned dist)
uses: actions/setup-node@v7
with:
# Single source of truth: .node-version at the repo root. This node
# only RUNS node_compat_matrix.mjs; the compat oracle is the pinned
# Node the runner downloads + SRI-verifies from external-tools.json.
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

- name: Node builtin compat matrix guard (--check, pinned oracle)
# Fails (exit 1) if any baselined cell got strictly worse or a
# prefix-parity invariant broke; improvements are accepted. The runner
# downloads + SRI-verifies the pinned Node dist under .cache/node-pin/.
run: |
set -euo pipefail
echo '### Node builtin compat matrix guard' >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
node scripts/node_compat_matrix.mjs --check \
| tee -a "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ target/
__pycache__/
*.py[cod]

# Pinned Node oracle for the builtin-module compat matrix
# (scripts/node_compat_matrix.mjs downloads + SRI-verifies + caches here).
.cache/node-pin/

# Android Gradle: caches and build outputs are regenerable. Source under
# android-build/ that we DO track: build.gradle.kts files, gradle wrapper,
# AndroidManifest.xml, Kotlin sources under app/src/main/java, and resources
Expand Down
22 changes: 21 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation.

**Current Version:** 0.5.1267
**Current Version:** 0.5.1268


## TypeScript Parity Status
Expand All @@ -27,6 +27,26 @@ Two workflows are deliberately exempt and say so inline: `node-core-subset.yml`
- **Test/CI mechanics** — `#794` (per-category parity thresholds), `#796` (gap-suite output truncation + O(n²) `normalize_output`), `#812` (42-module behavioral matrix), `#806/#807/#808` (test harnesses for mixins / async context / ≥300-init scale).
- **Skip-list audit** — `#797` covers `test-parity/known_failures.json` provenance (issue # + date per entry).

### Node builtin compatibility matrix (`scripts/node_compat_matrix.mjs`)

Breadth sweep over EVERY `require("module").builtinModules` entry, both import forms (`M` and `node:M`), against a **pinned, SRI-verified Node** (the "latest stable" oracle, pinned in `external-tools.json` `tools.node.version` — currently **26.5.1**, independent of the `.node-version` gap-suite oracle). It compares Perry's export-SHAPE fingerprint (sorted `name:typeof` over the module namespace + the default export's typeof) to the oracle's. This is the systematic version of the #812 "42-module behavioral matrix" — shape, not deep behavior (behavioral cases stay in the node-suite).

```bash
# FAST LOOP — reach for this first when iterating on ONE builtin:
node scripts/node_compat_matrix.mjs --module fs # one module, both forms
node scripts/node_compat_matrix.mjs --module fs,path,crypto # a few
node scripts/node_compat_matrix.mjs --module fs --method readFileSync,promises # only these exports
node scripts/node_compat_matrix.mjs --only fs.readFileSync,path.join # combined mod.export form
# (the pinned Node download is skipped once cached under .cache/node-pin/)

# FULL SWEEP + GATE:
node scripts/node_compat_matrix.mjs # whole matrix + summary table
node scripts/node_compat_matrix.mjs --check # CI gate: exit 1 on regressions vs the baseline
node scripts/node_compat_matrix.mjs --update-baseline # rewrite test-parity/node-compat-matrix.baseline.json
```

A `--module` selector scopes `--check`/`--update-baseline` to just that slice (a single-module refresh never rewrites the whole baseline). A `--method`/`--only` subset is a print-only fast diagnostic (it narrows the fingerprint, so it is refused for `--check`/`--update-baseline`). **Bump the pinned Node** by editing `tools.node.version` in `external-tools.json` (add per-platform sha512 SRI), then `--update-baseline` and review the diff. Needs the release binary (`cargo build --release -p perry`). Full page: `docs/src/testing/node-compat-matrix.md`.

**Known categorical gaps**: `console.dir`/`console.group*` formatting, lone surrogate handling (WTF-8). (Lookbehind regex is NOT a gap anymore: `perry-runtime/src/regex.rs` falls back from the `regex` crate to `fancy-regex` for lookbehind/backreferences, with capture-group translation and replacement expansion.)

## Workflow Requirements
Expand Down
Loading
Loading