Skip to content

test(gap): make the gap gate capable of passing (10 of 15 snapshot entries recorded an unreachable status) - #8198

Merged
proggeramlug merged 1 commit into
mainfrom
test/gap-gate-unreachable-node-fail
Aug 16, 2026
Merged

test(gap): make the gap gate capable of passing (10 of 15 snapshot entries recorded an unreachable status)#8198
proggeramlug merged 1 commit into
mainfrom
test/gap-gate-unreachable-node-fail

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Fixed — the gap gate could never be green

run_parity_tests.sh can only record node_fail via perry_abnormal_exit, which
matches signals and timeout only (124, 132/134/136/138/139, >128). Node's real
failures in this suite are a plain exit 1ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
for the enum and parameter-property tests (strip-only mode cannot run them, and
Node 26 dropped --experimental-transform-types), and MODULE_NOT_FOUND for the
npm ones. Those fall through to a normal comparison and come out parity_fail.

Ten of the fifteen gap_snapshot.json entries recorded node_fail, a status the
harness is structurally incapable of emitting.
gap_snapshot.py diff() therefore
returned changed for every one, and any diff makes it exit 1 — so the gate could
never pass, on any tree. It survived because parity is tag-gated and invisible
per-PR; conformance-smoke (which runs run_gap_tests.sh --shard N/8, the same
suite) is what surfaced it as 8/8 red shards in #8117.

This is the mirror of CLAUDE.md's "four ways a gate can be unable to fail": a
gate that cannot pass is equally uninformative, and rots the same way.

Resolved by category rather than by editing statuses — the schema says "do not
hand-edit", and hand-editing is how ten impossible statuses got there:

  • 3 TypeScript-syntax tests (test_gap_4510_enum_forward_ref,
    test_gap_derived_param_props, test_gap_enum_in_function_body) get
    test-parity/expected/*.txt fixtures — the channel the test_decorators_* tests
    already use for exactly this reason. Node can never run them, so the oracle was
    built with esbuild → node and cross-checked against the expectations written in
    each test's own header; Perry is byte-identical to all three. Note
    test_gap_derived_param_props already said "this is a perry-only expected-output
    test"
    — the fixture was simply never created, so it had verified nothing since May.
  • 6 npm tests (backoff_options, cron_cronjob, dayjs_factory_arg,
    moment_methods, ratelimiter_memory, slugify_options) had their packages
    declared as devDependencies. They were never in package.json, so the oracle could
    not run in any environment, CI includednpm ci would not install them
    either. .npmrc says the root npm install exists precisely to "materialize the
    parity-test fixture deps". All six now run under node with exit 0 and all six match
    Perry: live parity, which is stronger than a frozen fixture.
  • 1 remaining, re-triaged as a real Perry bug rather than a snapshot artifact.
    test_gap_prop_plan_cache_invalidation is written for sloppy mode but runs as ESM,
    which is strict, so its frozen-object writes throw. Node and Perry both correctly
    throw and differ only in the message: node names the constructor ('#<H>'), Perry
    hardcodes '#<Object>' at error.rs:1726, because
    js_throw_type_error_immutable_write takes (kind, key_ptr, key_len) and no
    receiver. Recorded with that root cause; the fix is a receiver-aware variant behind
    the existing throw_immutable_write wrapper (14 callers, no codegen ABI change).

The snapshot was then regenerated from a full 562-test run (UPDATE_SNAPSHOT=1),
not hand-edited: 99.1% parity, 5 non-passing entries, 0 crashes, and
gap_snapshot.py check exits 0. test_gap_iterator_helpers_2874, which had been
listed while passing, is gone.

Also fixed: scripts/gc_gate_wiring_check.py did not list check_gc_env_knobs.py
in GATES, so the gate-integrity checker could not see one of the gates it exists to
audit. Now 8 gates, self-test green.

Two things deliberately not done. SKIP_TESTS in run_parity_tests.sh is exact-match
and holds only legacy test_* names, so it can never match a test_gap_* test — left
alone because every current case is better served by the expected-output channel.
And test_gap_webcrypto_async_threadpool failed once during an unsharded verification
run at load ~64 and was not recorded: it asserts that an async digest crosses a
macrotask boundary, node printed false, and 5/5 re-runs at load ~45 print true,
matching Perry. The oracle flaked, and parking it would have converted a load artifact
into a permanently accepted failure.

Refs #8117.

Summary by CodeRabbit

  • Bug Fixes
    • Corrected parity reporting so Node execution failures are distinguished from genuine parity mismatches.
    • Reclassified an immutable-write discrepancy for clearer tracking and follow-up.
  • Tests
    • Updated expected results for enum handling, derived parameter properties, and nested parsing scenarios.
    • Refreshed parity snapshots to reflect current test outcomes and remove obsolete entries.
  • Chores
    • Improved validation of test-gate wiring and environment settings.
    • Added development tooling to support scheduling, retries, date handling, rate limiting, and slug generation.

Ten of fifteen gap_snapshot.json entries recorded node_fail, which
run_parity_tests.sh can only emit for a signal or timeout — never for the
plain exit 1 that node actually produces here. Every run diffed as
"changed", so the gate returned 1 unconditionally.

Fixed by category: expected-output fixtures for the three tests node can
never run, npm devDependencies for the six whose oracle could not resolve
its imports in any environment, and a root-caused entry for the one that
is a genuine Perry parity bug. Snapshot regenerated from a full 562-test
run rather than hand-edited: 99.1%, 5 entries, check exits 0.

Also registers check_gc_env_knobs.py in gc_gate_wiring_check.py's GATES,
which could not previously see it.

Refs #8117.
@proggeramlug
proggeramlug merged commit 6418563 into main Aug 16, 2026
32 of 54 checks passed
@proggeramlug
proggeramlug deleted the test/gap-gate-unreachable-node-fail branch August 16, 2026 09:13
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d667d95-f581-4e10-aee7-1ba36fc9bc2a

📥 Commits

Reviewing files that changed from the base of the PR and between bfb0707 and 97dd7e9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • changelog.d/8196-gap-gate-unreachable-node-fail.md
  • package.json
  • scripts/gc_gate_wiring_check.py
  • test-parity/expected/test_gap_4510_enum_forward_ref.txt
  • test-parity/expected/test_gap_derived_param_props.txt
  • test-parity/expected/test_gap_enum_in_function_body.txt
  • test-parity/gap_snapshot.json

📝 Walkthrough

Walkthrough

The change updates gap-test parity expectations and snapshot triage, adds development dependencies used by npm tests, registers lint gate validation, and documents the gap-gate results.

Changes

Gap parity gate updates

Layer / File(s) Summary
Parity fixtures and snapshot triage
test-parity/expected/*, test-parity/gap_snapshot.json, package.json
Adds expected outputs for three parity tests, reclassifies the immutable-write result as an open parity bug, and adds development dependencies.
Gate audit and change record
scripts/gc_gate_wiring_check.py, changelog.d/8196-gap-gate-unreachable-node-fail.md
Registers the lint job for GC environment-knob checks and documents the gap-gate triage and regenerated snapshot results.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

Suggested labels: parity, tooling

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/gap-gate-unreachable-node-fail

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

proggeramlug pushed a commit that referenced this pull request Aug 16, 2026
Measured on the 4-shard PR run: the slowest shard took 39.5 min because it
happened to receive 6 ext-routed tests, each of which triggers a ~4-5 min
auto-optimize runtime rebuild for a feature set the shard had not seen. Six
shards levels that at ~28 min, in line with gc-stress, for ~170 job-minutes
(was 480 for 8 auto-optimize shards).

The gap snapshot itself is main's (#8198 fixed the ten node_fail entries at
the source -- fixtures + npm devDependencies -- and regenerated it; the CI
re-baseline dispatch on this branch had reached the same 5 standing entries
plus those ten, so nothing else moved).
proggeramlug pushed a commit that referenced this pull request Aug 16, 2026
…eset step

* gap-suite: `npm ci --ignore-scripts --no-audit --no-fund` after setup-node so
  the six npm-fixture gap tests #8198 moved to root devDependencies have their
  oracle imports in CI.
* lint/changeset step: `jq -s -e` instead of `jq | grep -q`. `lint` is now a
  registered moving-GC gate (main registered check_gc_env_knobs there), and
  gc_gate_wiring_check rejects an unguarded pipe in a gating step; `-s` because
  `gh api --paginate` emits one array per page.
proggeramlug pushed a commit that referenced this pull request Aug 16, 2026
Measured on the 4-shard PR run: the slowest shard took 39.5 min because it
happened to receive 6 ext-routed tests, each of which triggers a ~4-5 min
auto-optimize runtime rebuild for a feature set the shard had not seen. Six
shards levels that at ~28 min, in line with gc-stress, for ~170 job-minutes
(was 480 for 8 auto-optimize shards).

The gap snapshot itself is main's (#8198 fixed the ten node_fail entries at
the source -- fixtures + npm devDependencies -- and regenerated it; the CI
re-baseline dispatch on this branch had reached the same 5 standing entries
plus those ten, so nothing else moved).
proggeramlug pushed a commit that referenced this pull request Aug 16, 2026
…eset step

* gap-suite: `npm ci --ignore-scripts --no-audit --no-fund` after setup-node so
  the six npm-fixture gap tests #8198 moved to root devDependencies have their
  oracle imports in CI.
* lint/changeset step: `jq -s -e` instead of `jq | grep -q`. `lint` is now a
  registered moving-GC gate (main registered check_gc_env_knobs there), and
  gc_gate_wiring_check rejects an unguarded pipe in a gating step; `-s` because
  `gh api --paginate` emits one array per page.
proggeramlug added a commit that referenced this pull request Aug 16, 2026
* ci: restructure CI into PR gate / main sweep / full suite tiers

One workflow, three tiers, one policy file. `scripts/ci_plan.py` decides
what a run of test.yml executes; every job is `needs: plan` + a plan flag;
the fan-in job (`pr-gate` / `main-gate` / `full-suite-gate`) is the single
status the outside world keys on.

* PR tier: lint, check (clippy x2 + api-docs-drift), warnings, scoped
  cargo-test, 4-shard fast-mode gap suite, gc-stress (PR subset),
  e2e-scoped, security-audit when deps changed. Docs-only PRs run lint
  only. `pr-gate` is the only required context.
* Sweep tier: every push to main, coalesced (constant concurrency group,
  cancel-in-progress off); PR tier unscoped + windows x2, gc-stress full,
  compiler-output-regression, repsel-census, harmonyos-smoke, binary-size,
  security-audit. Sweep-only jobs chain behind `check`.
* Full tier: nightly, tags, dispatch, `run-extended-tests` label; adds
  parity, compile-smoke (no more continue-on-error), 8-shard auto-optimize
  gap suite, doc-tests, package smokes, native-abi-evidence-packet.
  release-packages.yml dispatches `tier=full` and requires a successful
  `full-suite-gate` job on the SHA.
* Satellite gates (gc-*, tls-budget, auto-opt, eh-transport,
  llvm-inprocess, ext-link, container-tests): PR arm is opt-in via the
  `run-extended-tests` label; six-hourly / nightly main-line arms and tag
  arms unchanged. ext-link gains a nightly arm; container-tests drops its
  push:main arm.
* sccache saves only from main-line runs (PR saves were ~200 GB/day into a
  10 GB budget and unreadable by other PRs anyway); cache-warm.yml removed
  (the sweep is the cache-producing build on main now).
* security-audit.yml becomes workflow_call + weekly schedule.

Measured before: 14 workflows / 48 jobs / ~650 runner-min per PR push on a
20-slot org; 0/66 PR runs of Tests concluded; last 12 merges all bypassed
protection. Docs: docs/src/testing/ci-tiers.md.

* changelog: fragment for #8187 (CI tiers)

* ci: binary-size is report-only on macOS — full tier only

* docs: point CI-authority references at the tiered gate

* ci_plan: e2e-scoped needs a pull_request event, not just the pr tier

* ci: cargo-test target selection keys on the plan; scoped mode needs a pull_request event

* ci: 6 PR gap shards (measured), 3 in the sweep

Measured on the 4-shard PR run: the slowest shard took 39.5 min because it
happened to receive 6 ext-routed tests, each of which triggers a ~4-5 min
auto-optimize runtime rebuild for a feature set the shard had not seen. Six
shards levels that at ~28 min, in line with gc-stress, for ~170 job-minutes
(was 480 for 8 auto-optimize shards).

The gap snapshot itself is main's (#8198 fixed the ten node_fail entries at
the source -- fixtures + npm devDependencies -- and regenerated it; the CI
re-baseline dispatch on this branch had reached the same 5 standing entries
plus those ten, so nothing else moved).

* ci: npm ci before the gap suite (#8198 fixture deps); pipe-free changeset step

* gap-suite: `npm ci --ignore-scripts --no-audit --no-fund` after setup-node so
  the six npm-fixture gap tests #8198 moved to root devDependencies have their
  oracle imports in CI.
* lint/changeset step: `jq -s -e` instead of `jq | grep -q`. `lint` is now a
  registered moving-GC gate (main registered check_gc_env_knobs there), and
  gc_gate_wiring_check rejects an unguarded pipe in a gating step; `-s` because
  `gh api --paginate` emits one array per page.

---------

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
proggeramlug pushed a commit that referenced this pull request Aug 17, 2026
…e 6h cap

Run 31935729773's parity job was killed by GitHub's 6-hour job cap
(11:44->17:45, `cancelled`), so the release gate could not complete even in
principle. Now:

* `parity` is a plan-driven 8-shard matrix (`run_parity_tests.sh --shard
  N/8`, the same round-robin partition gap-suite uses), each shard also
  running `parity_known_failures.py` (shard-safe by design: an entry whose
  test is not in this shard is never flagged) and gets npm ci for the #8198
  oracle fixtures.
* `parity-aggregate` merges the shard reports via the new
  scripts/parity_report_merge.py (self-tested; REFUSES a missing shard with
  --expect so a lost artifact is a red run, not a smaller green suite;
  reproduces the harness's own percentage formula) and runs the two gates
  whose baselines only make sense on the whole suite: the threshold
  minimums (a 62%-floor category with two tests in a shard would flap) and
  the per-module matrix trend.
* `gate` fan-in requires parity-aggregate; ci_plan emits parity.total/shards.
* Dropped the stale "informational / does not block" comment block: since
  the tiering, a red parity fails full-suite-gate, which is what
  release-packages.yml keys on.
proggeramlug pushed a commit that referenced this pull request Aug 17, 2026
…e 6h cap

Run 31935729773's parity job was killed by GitHub's 6-hour job cap
(11:44->17:45, `cancelled`), so the release gate could not complete even in
principle. Now:

* `parity` is a plan-driven 8-shard matrix (`run_parity_tests.sh --shard
  N/8`, the same round-robin partition gap-suite uses), each shard also
  running `parity_known_failures.py` (shard-safe by design: an entry whose
  test is not in this shard is never flagged) and gets npm ci for the #8198
  oracle fixtures.
* `parity-aggregate` merges the shard reports via the new
  scripts/parity_report_merge.py (self-tested; REFUSES a missing shard with
  --expect so a lost artifact is a red run, not a smaller green suite;
  reproduces the harness's own percentage formula) and runs the two gates
  whose baselines only make sense on the whole suite: the threshold
  minimums (a 62%-floor category with two tests in a shard would flap) and
  the per-module matrix trend.
* `gate` fan-in requires parity-aggregate; ci_plan emits parity.total/shards.
* Dropped the stale "informational / does not block" comment block: since
  the tiering, a red parity fails full-suite-gate, which is what
  release-packages.yml keys on.
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