Skip to content

check_gc_env_knobs.py is wired into no workflow — it caught a real shipped bug only because someone ran it by hand #8166

Description

@proggeramlug

scripts/check_gc_env_knobs.py runs in no workflow

$ grep -rln check_gc_env_knobs --include=*.yml --include=*.sh --include=*.py .
  (only the script itself, plus gc-handoff/KNOBS-NOTES.md)

It is not in test.yml's lint job — I generated that job's real command list (27 invocations, lines 88–380) and it is absent — nor in any other workflow. gc_gate_wiring_check.py reports "GC gate wiring OK (7 gates main-line-reachable and able to fail)" without counting it, so the wiring checker does not know about it either.

This is CLAUDE.md's "★ Four ways a gate can be unable to fail", hazard 2, in its purest form: the gate exists, it works, and nothing runs it.

It works, and it just caught a real bug — locally, by hand

On main at 48935af78's parent it failed:

GC environment-knob drift check FAILED:
  - PERRY_GC_STACKMAP_TRACE: read for presence (var_os(..).is_some()/.is_none())
    in crates/perry-runtime/src/gc/roots/stack_maps.rs;
    'PERRY_GC_STACKMAP_TRACE=0' would ENABLE it.
    Use gc::env_flag_enabled (default-OFF) or gc::env_default_on_enabled (default-ON kill switch).

That is a genuine defect — #8131 introduced the knob with var_os(..).is_some(), so the spelling a reader is most likely to try, =0, turned the trace on. #8164 fixed it and the gate now passes (30 claimed knobs, 197 live env parsers, 3 historical documents exempt, 0 presence-only GC reads).

So the script earns its keep. It found a real bug in shipped code, on the first run. It simply never runs unless someone invokes it by hand — which is how #8131's knob reached main in the first place.

Correcting the record on #8164

#8164's changelog says the gate "failed on it, and a red lint on main blocks every open PR." The fix is right and should stay, but that justification is not accurate: lint was not red from this, because the gate is not in lint. Nothing in CI was red. The bug reached main and sat there precisely because no job would have caught it.

Worth stating plainly, because "a red gate forced this fix" and "no gate could have caught this" call for opposite follow-ups, and only the second one is true.

Ask

  1. Wire it into lint, next to the other scripts/*.py audits. It is fast and has a --self-test-style failure mode already.
  2. Teach gc_gate_wiring_check.py about it, so an unwired GC gate is itself a lint failure. That checker currently reports 7 gates as wired and cannot see the eighth that is not — which makes its "OK" narrower than it reads.
  3. Per CLAUDE.md's corollary, run it once on main before promoting it to required, so it does not immediately block every open PR.

Related

Same family as #8101's finding that parity and compile-smoke are required contexts that never run on an unlabeled PR. Between them, this repo currently has one gate that runs but cannot block, and two that block but cannot run.

Activity

  1. proggeramlug commented on Aug 16, 2026

    @proggeramlug
    ContributorAuthor

    Verified on 3be2016c1: the premise no longer holds.

    scripts/check_gc_env_knobs.py is wired into a workflow. .github/workflows/test.yml lines 281-282 run it inside the lint job (lint: opens at line 93, clippy: at 522, so 281 is squarely inside), under if: ${{ !cancelled() }}:

    python3 scripts/check_gc_env_knobs.py --self-test
    python3 scripts/check_gc_env_knobs.py
    

    It was added by 9da11218f (#7883) on 2026-08-11 — four days before this issue was filed. The knob-polarity defect it caught (var_os(..).is_some()) is fixed on main by 48935af78 (#8164). The grep behind this report must have run against a stale tree.

    One accurate residual, now fixed rather than deferred: scripts/gc_gate_wiring_check.py's GATES table did not list check_gc_env_knobs.py, so its "gates wired" verdict was one short — a gate-integrity checker that cannot see one of the gates. Folded into the gap-gate repair PR.

    Closing.

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