Repository navigation
Promote gc-ratchet to a required context now (precondition met); gc-stress after #8100 #8101
Description
Split out of #7737 item 4, which is closed as three-quarters done. This is the
remaining quarter, and the picture has moved twice since #7737 was filed —
in both directions — so it is worth stating the current one precisely.
What is true right now
gh api repos/PerryTS/perry/branches/main/protection --jq .required_status_checks.contexts
["lint","cargo-test","parity","compile-smoke","api-docs-drift","security-audit","conformance-smoke-complete"]
Neither gc-ratchet nor gc-stress is there. Both run, both can report red, neither
blocks a merge — CLAUDE.md's "four ways a gate can be unable to fail", hazard 2.
gc-ratchet: the precondition is now MET — promote it
CLAUDE.md's corollary is "a new gate has never been green, so promoting it to
required immediately blocks every open PR. Run it once, then promote." On
2026-08-12 that was the blocker: gc-ratchet had 0 successes in its last 30 main
runs. That is no longer the case. Its last four main runs are all green, on the
four consecutive main commits immediately preceding 0d7fe21b0:
| run | when (UTC+2) | main sha |
conclusion |
|---|---|---|---|
31766259491 |
2026-08-14 03:15 | f9475fb9a |
success |
31781155927 |
2026-08-14 07:45 | 78d0afa46 |
success |
31805278312 |
2026-08-14 13:33 | 5c27d1ad9 |
success |
31831865551 |
2026-08-14 19:07 | 506f4ab11 |
success |
The flip is attributable: f9475fb9a is fix(gc): attribute deterministic ratchet shifts (#8069), the last touch of baseline/gc-ratchet-v1.json, and the first green
run is the one at that commit. #8051 — the attribution blocker the previous triage
named — is closed. So is #7966.
The green is not vacuous — the gate's subject ran. Run 31831865551 measured all
fourteen probes and ended gc-ratchet: OK; e.g.
14_grow_then_churn: correctness=pass heap_used_bytes=0% heap_total_bytes=0% rss_bytes=0.075594% peak_rss_bytes=0.080871% wall_ms=17.099233%
12_large_live_set: correctness=pass heap_used_bytes=0% heap_total_bytes=0% rss_bytes=0.8705% peak_rss_bytes=0.857633% wall_ms=19.992527%
12_large_live_set's heap_used_bytes / heap_total_bytes cells are the exact cells
#7737 said were advisory-only, and they are gating rows with a 0% delta today.
Admin action, once:
gh api -X PATCH repos/PerryTS/perry/branches/main/protection/required_status_checks \
-f 'contexts[]=lint' -f 'contexts[]=cargo-test' -f 'contexts[]=parity' \
-f 'contexts[]=compile-smoke' -f 'contexts[]=api-docs-drift' \
-f 'contexts[]=security-audit' -f 'contexts[]=conformance-smoke-complete' \
-f 'contexts[]=gc-ratchet'Caveat worth weighing before pressing it: gc-ratchet.yml fires on schedule +
push, and this repo's push: on the test workflows is tags-only. Check that the
context actually reports on pull requests before making it required, or every PR
will sit forever on a check that never arrives — that is a different way to block
every open PR than the one CLAUDE.md warns about, with the same effect. Confirm on
one PR first.
gc-stress: still red, and for exactly ONE reason — see the linked bug
Eight consecutive nightly test.yml runs on main, 2026-08-07 through 2026-08-14,
all report gc-stress=failure (31150713440, 31240304595, 31295652054,
31358183869, 31460223673, 31566481914, 31670425699, 31772993217).
The most recent one narrows to a single row of scripts/gc_repsel_matrix.sh:
summary: PASS=1230 UNVER=310 XFAIL=0 FAIL=22
specabi_reassign FAIL FAIL FAIL ... FAIL <- 22 of 22 arms, INCLUDING shipped_default
Every other row is PASS or UNVER. It is not a GC-arm failure: it fails with
cycles=0 evacuated=0 scavenged=0 reclaimed=0 in several arms, it fails under
shipped_default requires=none, and every repsel kill switch leaves it broken.
Filed as #8100 with a five-line reproducer and a root cause: element reads on a
binding whose initializer was new Int32Array(...) lower to an unguarded
js_typed_array_get, and that helper answers 0.0 when clean_ta_ptr rejects the
receiver instead of falling back to the ordinary [[Get]]. Fixing #8100 is the whole
of what stands between gc-stress and a green main run.
There was also a SECOND, now-resolved cause worth recording so nobody re-derives it:
the 2026-08-08/09 runs (31240304595, 31295652054) had FAIL=0 in the matrix and
were red on the liveness gate instead — four arms (default, verify_evac,
cons_scan_off, cons_scan_off_force) flagged STALE-REGISTRY, listed in
scripts/gc_matrix_inert_arms.txt as known-inert while actually satisfying
requires=scavenge on 41/58 cells. That is gone in the 2026-08-14 run: every arm now
prints live.
Ordering
- Promote
gc-ratchetnow (precondition met), after confirming it reports on a PR. - Fix Reassigning a
new Int32Arraybinding to a plain array makes every element READ return 0 (silent miscompile; sole reasongc-stressis red) #8100 (specabi_reassign). - Observe
gc-stressgreen onmainonce. - Promote
gc-stress.
Note also #8092: lint and cargo-test are currently red for every PR, so the
required-context set is already being bypassed at merge time. Promoting a gate into a
set that is routinely bypassed buys less than it looks like it does; worth resolving
#8092 alongside.
Activity
proggeramlug commentedon Aug 14, 2026
Independently verified both halves of the precondition.
gc-ratchetis ready to promote;gc-stressis not, for exactly the reason stated.gc-ratchet— green onmainAND on PRsCLAUDE.md's rule is "run it once, then promote", because a gate that has never been green blocks every open PR the moment it becomes required. Both directions check out:
main, last eight runs — four consecutive successes, immediately after four failures, so the flip is attributable rather than incidental:And the caveat this issue itself raises — does the context actually report on a pull request — holds. Four recent PRs, all
SUCCESS:That was worth checking separately: a job can be green on
mainand still never produce a check run on a PR, which is precisely the stateparityandcompile-smokeare in today (they reportSKIPPED).gc-ratchetis not in that state.gc-stress— correctly blocked on #8100Consistent with the single-cause diagnosis:
specabi_reassignfails 22 of 22 matrix arms includingshipped_default. An agent is on #8100 now. Promotinggc-stressbefore that lands would make every PR unmergeable, which is the opposite of the point.What I am not doing
Editing branch protection is an outward-facing, hard-to-reverse repository configuration change that affects every contributor, so I am not making it unilaterally — surfacing it to the maintainer with the evidence above instead.
Worth sequencing against #8092 when it happens: the required list currently contains two contexts that report
SKIPPEDon every PR (parity,compile-smoke— informational by design since v0.5.1018, bothcontinue-on-error: true) and two that are red for everyone (cargo-test,conformance-smoke-complete, the latter failing 8 of 8 shards). Adding a genuinely-green gate to that list is good; it would be better still alongside removing the two that cannot be satisfied.proggeramlug commentedon Aug 15, 2026
Maintainer decision: fix the existing required set first
Holding this promotion. The precondition I verified is genuinely met —
gc-ratchetis green onmainfor four consecutive runs after four failures, and reports SUCCESS on four separate PRs, so unlikeparity/compile-smokeit actually runs pre-merge. That is not in question.The reason to wait is what #8117 established since: the required set is currently unsatisfiable.
conformance-smokefails 8 of 8 shards for ten real reasons, andcargo-testfails on four ELF-only byte-identity tests. Adding a genuinely-green gate to a list that no PR can satisfy does not protect anything — every merge still goes through admin bypass, which is the habit that let #8100 (a silent wrong-answer miscompile in the shipped default) sit unnoticed for days behind a cancelled shard.So the sequence is:
conformance-smokefails 8/8 shards: 12 real regressions, 10 newly-visible node_fail transitions, 1 fix the snapshot hasn't accepted #8117 tracks ten remaining regressions, now down from twelve —array_methodsfixed by fix(array): ask the typed-array question before clean_arr_ptr rejects it, for sort/toSorted/toReversed/with #8119 andspecabi_reassignby fix(typedarray): dispatch, not just validate, when the element-read receiver is not a typed array #8109. Two of the ten are crashes, two are ordering-dependent (do not bisect those before establishing isolation), and two look like one bug.gc-ratchet, at which pointrequiredmeans something again.gc-stressafter Reassigning anew Int32Arraybinding to a plain array makes every element READ return 0 (silent miscompile; sole reasongc-stressis red) #8100's family fully clears — it was blocked on exactly that and fix(typedarray): dispatch, not just validate, when the element-read receiver is not a typed array #8109 has landed part of it.Worth deciding alongside step 2:
parityandcompile-smokeare in the required list while reportingSKIPPEDon every PR by design (tag-gated since v0.5.1018, bothcontinue-on-error: true). Removing them would leave a required list containing only contexts that actually run pre-merge, which is the property that makes the list mean anything.Nothing here is lost — the verification stands and the promotion is a one-command change once the set is clean.
proggeramlug commentedon Aug 15, 2026
Status: the
gc-ratchetcase is sound, and the thing blocking it just got much smallerNot promoting yet — the owner's call on this was "fix the existing required set first", and promoting a new context into a set that is already unsatisfiable would just add another forced admin bypass. Recording where that stands, because it moved a lot today.
The blocker was
conformance-smoke-complete, and it is now 3 failures, not 12conformance-smoke-completeis in the required set and is red onmain— which is why every merge today went in under--admin. That is #8117.I re-ran all twelve of #8117's
pass -> Xregressions against currentmain(fb87d8923) on a fresh perry-dev build, byte-compared against node 26.5.1. Nine now pass. All threepass -> crashentries are gone — two were a single bug (a missing Buffer/DataView arm inobj_value_has_own_key, #8141) andspecabi_reassignwas #8100/#8109. The remainder cleared with #8090/#8109/#8119/#8120/#8134/#8135. Full table in #8117.Three remain, and they are in flight:
test_gap_collection_foreach_member_receiver_thisargtest_gap_set_map_foreach_fused_receiver(almost certainly the same bug as the above)test_gap_sso_concat_string_index(string indexing returnsundefinedafter an SSO concat — the worst of the three)Caveat I want on the record: my harness compiles and
cmps directly, while the real gate appliesnormalize_output. So the nine are "very likely clear" rather than proven clear, and the next fullconformance-smokerun onmainis what should be trusted. I would rather flag that than have the required set declared satisfiable on my numbers and find it still red.gc-ratchet's own precondition is still metNothing here changes this issue's argument. The four consecutive green
mainruns stand, the flip is attributable to #8069, and the green is non-vacuous — run31831865551measured all fourteen probes and reported per-probe deltas, so the subject demonstrably ran rather than the job merely not throwing. That is the check CLAUDE.md's hazard 4 asks for, and it passes.Sequence
conformance-smoke-completegoes green on a realmainrun — not on my local recount.gc-ratchetinto the required contexts, at which point it costs nothing because the set is satisfiable again.Worth noting for step 3:
parityandcompile-smokeare also in the required set but are tag-gated and never run on a PR, so they can never report success there. Whatever "satisfiable" means operationally, it has to account for those two as well — otherwise promotion is blocked on a condition that cannot be met regardless of #8117. That is a separate decision from this issue's, but it lands in the same place, so someone should make it deliberately rather than discover it at promotion time.proggeramlug commentedon Aug 16, 2026
Re-checked today: the window opened, and then closed again a few hours ago
Short version: everything this issue asked for as a precondition is now true except one thing that broke today, and that one thing has a fix already open. Not promoting yet, and here is the checkable reason rather than a judgement call.
The two side-conditions from the earlier comments are resolved
gh api repos/PerryTS/perry/branches/main/protection --jq .required_status_checks.contextsparityandcompile-smokeare gone — that was the "remove the two contexts that reportSKIPPEDon every PR by design" recommendation from the 2026-08-15 comments, and it has since been done. #8117 is closed. #8100 is closed.gc-stress: this issue's step 3 is satisfiedThe
gc-stressjob is green on the last two nightlymainruns, after eight consecutive failures:Consistent with the single-cause diagnosis:
specabi_reassignwas #8100, closed by #8109. Worth recording alongside it that the job-levelcontinue-on-errorthis issue's hazard-1 concern was about is gone — the onlycontinue-on-error: trueleft in thegc-stressblock is step-level, on the deliberately-informational write-barrier stress hunt (~200s nondeterministic corruption-window hunts (#5029)). The job itself can fail and does reportfailure.gc-ratchet: the streak was 11 long, and#8204ended it this afternoonThe run of green
mainruns extended well past the four this issue was filed on — eleven consecutive,f9475fb9a(2026-08-14) throughba2ecaacd(2026-08-16T12:56). Then:bf8fd868eis not an ancestor ofba2ecaacd— it landed after the last gc-ratchetmainrun, and it full-re-pinnedbenchmarks/gc_ratchet/baseline/gc-ratchet-v1.json. A full re-pin correctly ships noaccepted_deterministic_deltasreceipt (that key is the audit trail for a selective re-pin), but three of the ratchet's own self-tests hard-subscript it. Checked againstorigin/maincontent directly rather than inferred from CI:So
gc-ratchetis red onmainHEAD, and red on every branch based at or afterbf8fd868e— observed on #8203, #8209, #8210 (e.g. run31953454021). Promoting it right now would make every open PR unmergeable, which is exactly the CLAUDE.md corollary this issue quotes in its own opening.The part worth flagging beyond the immediate breakage:
main's green record does not show this yet, because nogc-ratchetrun has executed on a commit at or afterbf8fd868e. The last-N-runs check that this issue and its first comment both used as the promotion test would have read "eleven green, promote" at any point today and been wrong. A freshness check on the commit the streak covers, not just the count, is what distinguishes those two states.#8214 is the fix and is open, test-only, and sabotage-tested. It keeps the validator tests (rebuilding their fixture synthetically instead of assuming the pin carries a receipt), drops #8069's 21 frozen cells, and adds the case nothing covered: a full re-pin with no receipt is valid.
One new consideration that did not exist when this was filed
#8187 (
ci: restructure CI into PR gate / main sweep / full suite tiers) is open, and on that PRgc-ratchetreportsskipping. Ifgc-ratchetbecomes required and #8187 then lands, the context becomes a skipped check — which branch protection treats as a pass. That is hazard 4 wearing yet another hat: required, always green, subject never ran. Whichever of the two lands first, the other needs a deliberate re-check rather than an assumption.Updated ordering
windows-buildon every open PR.)gc-ratchetmainrun green on a commit at or after that merge — the commit, not the count.gc-ratchet, sequenced deliberately against ci: restructure CI into PR gate / main sweep / full suite tiers #8187 so it does not become a skipped-and-therefore-passing context.gc-stress— its own precondition is already met (two green nightlies, Reassigning anew Int32Arraybinding to a plain array makes every element READ return 0 (silent miscompile; sole reasongc-stressis red) #8100 closed).Still true that #8092 is open:
cargo-testis red on the nightly full-workspacemainrun (31926695806), so the required set is not yet satisfiable end-to-end, and merges continue to bypass. That does not block steps 1-2, and it is the reason not to treat step 3 as urgent.proggeramlug commentedon Aug 16, 2026
gc-ratchetis now a required context#8214 merged as
2e7a12818(currentmainHEAD), which clears the breakage recorded in the previous comment. Verified before pressing, in both directions:The self-tests actually pass on the new tree — not inferred from CI:
And a real
mainrun on that exact commit is green, non-vacuously.gc-ratchetsweepsmainon a six-hourly cron rather than per-merge, so rather than wait for the next window I dispatched run31960548698against2e7a12818. All fourteen probes measured and the checker rendered a verdict — hazard 4, "a gate must assert its subject was live":Promoted by append (the branch is
strict: false, so nothing else in the object moved):gh api -X POST repos/PerryTS/perry/branches/main/protection/required_status_checks/contexts \ -f 'contexts[]=gc-ratchet'Reverting is symmetric —
-X DELETEon the same endpoint with the same field.Two things that came out of doing it, both worth acting on separately
1. The queue, not the job, is now the cost. The dispatched run waited 60 minutes for a macOS runner (17:05 → 18:06 UTC) and then executed in 14. Every PR-side
gc-ratchetrun started in the hour after #8214 merged is stillqueuedor wascancelledby a superseding push — there is not yet a single completed PR-side run on post-#8214 code. So the practical merge cost of this context is ~75 minutes, not ~14, and it is now merge-blocking rather than merely advisory. That is #7856's starvation showing up on the PR lane instead of themainlane;docs/src/testing/ci-gate-scheduling.mdis the writeup, and this promotion converts it from an invisible problem into a felt one. If PR-side runs keep getting starved, the honest fix is cutting total job demand (which is what #8187 is for), not reverting this.2. Sequence against #8187 deliberately. On #8187 this context reports
skipping, and branch protection treats a skipped required check as a pass. If #8187 lands as-is now thatgc-ratchetis required, the gate becomes required-and-always-green — hazard 4 again, in the form this issue was filed to prevent. Whoever merges #8187 needs to re-check thatgc-ratchetstill produces a real conclusion on PRs, rather than assume it.gc-stress: precondition met, deliberately NOT promotedIts technical case is now clean — two consecutive green nightly
mainruns (31864245512@83b6b8c69,31926695806@0eccf7929) after eight failures, #8100 closed by #8109, and no job-levelcontinue-on-error(the surviving one is step-level, on the deliberately-informational write-barrier hunt).What is not clean is the cost.
gc-stressis atest.ymljob with a 90-minute timeout, and at this repo's merge cadence its PR runs are routinely unfinished at merge time —cancelledorqueuedon #8207, #8211, #8212 and #8216. Requiring it means every merge waits on a fulltest.ymlrun. That is a scheduling decision, not a correctness one, and it should be made explicitly rather than as a side effect of this issue. Leaving this open for that call.proggeramlug commentedon Aug 16, 2026
Closing: superseded by #8187's tiering
gc-ratchetwas promoted into the required contexts earlier today on a verified precondition (#8214 merged as2e7a12818; dispatched run31960548698measured all fourteen probes on that exact commit and reportedgc-ratchet: OK). That promotion has been reverted, and this issue is closed as superseded — because #8187 merged at2026-08-16T18:03:02Z, roughly an hour later, and changed the premise the whole issue rests on.Why the promotion stopped meaning anything
#8187 moves every satellite gate's PR arm behind an opt-in label.
gc-ratchet.yml's job now reads:So on an unlabeled PR the check run is created with conclusion
skipped, which branch protection accepts. Verified on #8242 and #8215 — both showgc-ratchet=skipped, and on #8242gh pr checks --requiredlistsgc-ratchetasskipping.That is a required context that is green without running: CLAUDE.md hazard 4, produced by this issue's own remedy. A gate that cannot fail is worse than an advisory one, because the required list is the thing people trust. Removing it is the honest state:
gh api -X DELETE repos/PerryTS/perry/branches/main/protection/required_status_checks/contexts \ -f 'contexts[]=gc-ratchet'Nothing about the gate's actual coverage changed by removing it: the six-hourly
mainsweep arm is untouched, it still fails loudly, andgate-freshness.ymlis the detector for it going dark — which, after #7856, is the property that actually mattered.gc-stress: deliberately not promotedRecording this as a decision rather than an omission. Its technical precondition is met — two consecutive green nightlies (
31864245512@83b6b8c69,31926695806@0eccf7929) after eight failures, #8100 closed by #8109, and no job-levelcontinue-on-error.It is not being promoted because #8187 gives a better answer than a standalone required context:
gc-stressnow runs as a PR subset in the PR tier and full in the sweep tier, fanning intopr-gate. Requiring the old standalone job name on top of that would mean every merge waits on a 90-minute job whose PR runs were already routinelycancelledat merge time (#8207, #8211, #8212, #8216).What replaces this issue
#8187's design statement is "
pr-gateis the only required context." Making the required list match that — and removing the contexts the new tiering no longer emits under those names — is the remaining work, and it belongs to #8092, which is open and is precisely about the required set not being satisfiable. Worth noting there that the required list has already drifted during today's transition and currently reads["lint","cargo-test","security-audit"]with nopr-gatein it.Both halves of this issue are now settled:
gc-ratchetpromoted, measured, and correctly reverted;gc-stressdecided against with the reason on the record.