PERRY_JSON_TAPE=0 + PERRY_GC_FROMSPACE_SCAN=1 over a parse-then-churn workload is now a known-good end-to-end detector for the whole layout-state family. #7643 measured it: with the JSON materialiser's finalize sabotaged to (ptr, /* saw_pointer */ false) it reports dangling=8000 owners=4000 and the binary SIGBUSes; clean it reports dangling=0 and exits 0.
Nothing runs it in CI. #7643's four unit tests cover the enumerator and the relocation invariant workload-free, which is the right primary guard — but they cannot catch a new materialiser path that forgets to finalize at all, because such a path would simply not be in the test.
What the gate must assert — both halves:
dangling=0 in the from-space scan output, and
- that a copying minor actually ran (
copied_objects > 0).
Half 2 is not optional. This repo has shipped three gates that were green while their subject never executed (PERRY_GC_FORCE_EVACUATE inert for every gc()-driven test, #6942/#6946; the matrix's --pressure knob disabling the path it measured, #7024; a moved= counter summing two collectors, #7025). A parse-then-churn workload that happens not to trigger a copying minor would report dangling=0 and mean nothing.
Also gate PERRY_JSON_TAPE=0 itself. The whole point of #7635's dead end was that the default lazy path materialises records after the last collection. A future default change that routes this workload lazily again would silently return the gate to vacuity — so the gate should assert the parse it is measuring was eager (record count materialised before the churn, or an equivalent observable).
Not required-on-merge until it has one observed green run on main — a new gate has never been green, so promoting it immediately blocks every open PR (CLAUDE.md, "four ways a gate can be unable to fail", corollary).
Context: #7635, #7633, #7643.
PERRY_JSON_TAPE=0+PERRY_GC_FROMSPACE_SCAN=1over a parse-then-churn workload is now a known-good end-to-end detector for the whole layout-state family. #7643 measured it: with the JSON materialiser's finalize sabotaged to(ptr, /* saw_pointer */ false)it reportsdangling=8000 owners=4000and the binary SIGBUSes; clean it reportsdangling=0and exits 0.Nothing runs it in CI. #7643's four unit tests cover the enumerator and the relocation invariant workload-free, which is the right primary guard — but they cannot catch a new materialiser path that forgets to finalize at all, because such a path would simply not be in the test.
What the gate must assert — both halves:
dangling=0in the from-space scan output, andcopied_objects > 0).Half 2 is not optional. This repo has shipped three gates that were green while their subject never executed (
PERRY_GC_FORCE_EVACUATEinert for everygc()-driven test, #6942/#6946; the matrix's--pressureknob disabling the path it measured, #7024; amoved=counter summing two collectors, #7025). A parse-then-churn workload that happens not to trigger a copying minor would reportdangling=0and mean nothing.Also gate
PERRY_JSON_TAPE=0itself. The whole point of #7635's dead end was that the default lazy path materialises records after the last collection. A future default change that routes this workload lazily again would silently return the gate to vacuity — so the gate should assert the parse it is measuring was eager (record count materialised before the churn, or an equivalent observable).Not required-on-merge until it has one observed green run on
main— a new gate has never been green, so promoting it immediately blocks every open PR (CLAUDE.md, "four ways a gate can be unable to fail", corollary).Context: #7635, #7633, #7643.