Repository navigation
Promote gc-ratchet to a required context now (precondition met); gc-stress after #8100 #8101
Description
Activity
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:success 506f4ab11 08-14T19:07 success 5c27d1ad9 08-14T13:33 success 78d0afa46 08-14T07:45 success f9475fb9a 08-14T03:15 <- #8069 lands here failure 0da668c95 08-14T02:38 failure 3381e1b89 08-13T19:15 failure 971d6ffb6 08-13T13:38 failure 81a88de40 08-13T07:47And the caveat this issue itself raises — does the context actually report on a pull request — holds. Four recent PRs, all
SUCCESS:PR 8086 gc-ratchet=SUCCESS PR 8090 gc-ratchet=SUCCESS PR 8091 gc-ratchet=SUCCESS PR 8087 gc-ratchet=SUCCESSThat 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 #8100PR 8086 gc-stress=FAILURE PR 8090 gc-stress=FAILURE PR 8091 gc-stress=CANCELLED PR 8087 gc-stress=CANCELLEDConsistent 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.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:
- Clear the required set.
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. - Then promote
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.
- Clear the required set.
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
- Land the three fixes above.
- Confirm
conformance-smoke-completegoes green on a realmainrun — not on my local recount. - Then promote
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.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.contexts["lint","cargo-test","api-docs-drift","security-audit","conformance-smoke-complete"]parityandcompile-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:31926695806 0eccf7929 2026-08-16T04:27 gc-stress=success 31864245512 83b6b8c69 2026-08-15T04:22 gc-stress=success 31772993217 601a02d23 2026-08-14T05:26 gc-stress=failure 31670425699 59cf9d9c9 2026-08-13T05:28 gc-stress=failure 31566481914 c4b2c1c8e 2026-08-12T05:25 gc-stress=failureConsistent 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:bf8fd868e perf(gc, codegen): recover the instruction cost of the 56 B -> 48 B header shrink (#8122) (#8204)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:$ git show origin/main:benchmarks/gc_ratchet/baseline/gc-ratchet-v1.json | \ python3 -c "import json,sys; print('accepted_deterministic_deltas' in json.load(sys.stdin))" False $ python3 -m unittest tests.test_gc_ratchet # origin/main tree ERROR: test_selective_refresh_names_every_accepted_cell_and_cause KeyError: 'accepted_deterministic_deltas' ERROR: test_selective_refresh_receipt_cannot_disagree_with_the_pin KeyError: 'accepted_deterministic_deltas' ERROR: test_selective_refresh_receipt_rejects_a_malformed_timestamp KeyError: 'accepted_deterministic_deltas' Ran 97 testsSo
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
- Land test(gc-ratchet): stop the self-tests demanding a selective re-pin receipt #8214. (Blocks everything else here; also unbreaks
windows-buildon every open PR.) - Observe one
gc-ratchetmainrun green on a commit at or after that merge — the commit, not the count. - Promote
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. - Promote
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.- Land test(gc-ratchet): stop the self-tests demanding a selective re-pin receipt #8214. (Blocks everything else here; also unbreaks
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:
$ python3 -m unittest tests.test_gc_ratchet # origin/main @ 2e7a12818 Ran 98 tests in 8.719s OK (skipped=2)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":01_nursery_churn: correctness=pass heap_used_bytes=0% heap_total_bytes=0% rss_bytes=0.341297% ... 12_large_live_set: correctness=pass heap_used_bytes=0% heap_total_bytes=0% rss_bytes=0.040328% ... 14_grow_then_churn: correctness=pass heap_used_bytes=0% heap_total_bytes=0% rss_bytes=0.108733% ... gc-ratchet: OKPromoted 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'["lint","cargo-test","api-docs-drift","security-audit","conformance-smoke-complete","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.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:if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-extended-tests')
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.
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.contextsNeither
gc-ratchetnorgc-stressis there. Both run, both can report red, neitherblocks a merge — CLAUDE.md's "four ways a gate can be unable to fail", hazard 2.
gc-ratchet: the precondition is now MET — promote itCLAUDE.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-ratchethad 0 successes in its last 30mainruns. That is no longer the case. Its last four
mainruns are all green, on thefour consecutive
maincommits immediately preceding0d7fe21b0:mainsha31766259491f9475fb9a3178115592778d0afa46318052783125c27d1ad931831865551506f4ab11The flip is attributable:
f9475fb9aisfix(gc): attribute deterministic ratchet shifts (#8069), the last touch ofbaseline/gc-ratchet-v1.json, and the first greenrun 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
31831865551measured allfourteen probes and ended
gc-ratchet: OK; e.g.12_large_live_set'sheap_used_bytes/heap_total_bytescells are the exact cells#7737 said were advisory-only, and they are gating rows with a 0% delta today.
Admin action, once:
Caveat worth weighing before pressing it:
gc-ratchet.ymlfires onschedule+push, and this repo'spush:on the test workflows is tags-only. Check that thecontext 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 bugEight consecutive nightly
test.ymlruns onmain, 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:Every other row is PASS or UNVER. It is not a GC-arm failure: it fails with
cycles=0 evacuated=0 scavenged=0 reclaimed=0in several arms, it fails undershipped_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 unguardedjs_typed_array_get, and that helper answers0.0whenclean_ta_ptrrejects thereceiver instead of falling back to the ordinary
[[Get]]. Fixing #8100 is the wholeof what stands between
gc-stressand a greenmainrun.There was also a SECOND, now-resolved cause worth recording so nobody re-derives it:
the 2026-08-08/09 runs (
31240304595,31295652054) hadFAIL=0in the matrix andwere red on the liveness gate instead — four arms (
default,verify_evac,cons_scan_off,cons_scan_off_force) flaggedSTALE-REGISTRY, listed inscripts/gc_matrix_inert_arms.txtas known-inert while actually satisfyingrequires=scavengeon 41/58 cells. That is gone in the 2026-08-14 run: every arm nowprints
live.Ordering
gc-ratchetnow (precondition met), after confirming it reports on a PR.new Int32Arraybinding to a plain array makes every element READ return 0 (silent miscompile; sole reasongc-stressis red) #8100 (specabi_reassign).gc-stressgreen onmainonce.gc-stress.Note also #8092:
lintandcargo-testare currently red for every PR, so therequired-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.