Skip to content

ci: the per-PR repsel matrix arms cannot reproduce the relocating-minor defect class (evac base is push-only) #6993

Closed

Description

@proggeramlug

The hole

scripts/gc_repsel_matrix.sh runs on pull requests with --arms pr:

PR_ARMS="default,verify_evac,cons_scan_off,shipped_default"

and on push with --arms all (.github/workflows/test.yml, gc-stress job).

But the evacuating base that #6981 established as the discriminator needs both halves together:

PERRY_GC_INCREMENTAL=0 PERRY_CONSERVATIVE_STACK_SCAN=off

and that combination appears only in --arms all (evac_minor / cons_scan_off_force). cons_scan_off on its own is pressure + precise roots with incremental mode still on, which does not take the relocating path.

Measurement

Built the five #6982 crashers from aa1c15028 (i.e. unfixed) and ran each PR-gated arm. All green:

                        default  verify_evac  cons_scan_off  shipped_default
repsel_canonical_i32    0        0            0              0
typedarray_param_read   0        0            0              0

The same binaries crash immediately under PERRY_GC_HEAP_LIMIT=8 PERRY_GC_INCREMENTAL=0 PERRY_CONSERVATIVE_STACK_SCAN=off (SIGBUS/SIGSEGV, copied_objects 4 579 / 5 965).

So the entire "raw reference held across a relocating collection" class — #6951, #6972, #6982, #6991, #6992 — is invisible to the per-PR gate. It can only go red after merge, on push.

Why I did not just fix it

Adding evac_minor to PR_ARMS today would fail every PR: 13 of 21 corpus cells are still red on that arm (2 crashes + 11 mismatches after #6982's fix). The gate has to become green-able first.

Suggested shape

  1. Land the outstanding rooting fixes (fix(gc): operand temporaries are precise roots — collection methods, constructor args, string-method receiver (#6970, #6969, #6971) #6983, gc: compiled constructor receiver goes stale across the globalThis-population collection (unmasked by #6982) #6991, gc: proven-this method value is lost across a relocating minor (TypeError: bump is not a function) #6992, gc: scalar-replaced object/array locals holding heap values are not precise roots #6968) until the evac_minor column is green or has a documented, enumerated skip list.
  2. Then add evac_minor to PR_ARMS, with the remaining known-red cells in an explicit allowlist (same provenance discipline as test-parity/known_failures.json, cf. test-parity: audit known_failures.json — every entry needs an issue # and date #797) so new breakage is caught but known breakage does not block.
  3. Until then, consider a non-blocking evac_minor PR run so the signal is at least visible on the PR page rather than only after merge.

Related: #6981, #6982, #6991, #6992, #6977, #6950.

Activity

  1. proggeramlug commented on Jul 30, 2026

    @proggeramlug
    ContributorAuthor

    Datapoint for this issue's thesis, from a GC measurement run (#7056): the relocating-minor defect class reproduces in the shipped default configuration, with no special arm at all.

    #7055 is an ordinary event-loop TypeScript program that produces a deterministic wrong checksum under plain perry file.ts -o bin && ./bin. The discriminator is exactly copied_objects > 0:

    arm minors @600 copied checksum
    shipped default 56 11,661,882 wrong
    PERRY_GC_SCAVENGE_NURSERY_MB=128 3 0 correct
    PERRY_GC_MOVING_LOOP_POLLS=0 1 0 correct
    PERRY_GC_MOVING_LOOP_POLLS=0 PERRY_GC_SCAVENGE=1 60 11,351,683 wrong

    Note the second row: three minor cycles, right answer, because none of them relocated.

    This bears on the "suggested shape" here in two ways.

    The gate hole may be wider than evac_minor. This issue frames the missing coverage as the PERRY_GC_INCREMENTAL=0 PERRY_CONSERVATIVE_STACK_SCAN=off combination that only --arms all reaches. But the case above needs neither half — it is the default. PERRY_GC_TRACE=1 on the shipped arm shows root_sources.native_stack_fallback.decision = "skip_disabled" on 62 of 63 cycles, so the shipped moving path is already running with precise roots and no conservative scan. #6981's reasoning that gc_check_trigger's forced force_full_scan() keeps this class out of production does not cover the deferred/moving path.

    What a green-able discriminator might key on. Since the discriminator here is copied_objects > 0 rather than any particular arm, a cheaper gate than adding evac_minor to PR_ARMS may be available: run the corpus in the default configuration but fail if a test that relocated disagrees with a copied_objects == 0 run of the same binary. That is a self-checking property (no oracle needed beyond Perry-vs-Perry), it does not require the 13-of-21 red cells to be fixed first, and it would have caught #7055 on the PR that introduced it.

    Full measurement context, including the per-cycle trace figures quoted above: #7056.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions