Summary
Two required status contexts, lint and cargo-test, currently fail for every pull request, including on trees that change nothing related to them. lint also fails on a pristine origin/main checkout. While that holds, neither context can distinguish a good PR from a bad one, and every merge necessarily goes through admin bypass.
This is the CLAUDE.md "★ four ways a gate can be unable to fail" pattern in its most expensive form: the jobs run, genuinely report failure, and are required — so the only way to land anything is to ignore them, which trains the team to ignore them for the PR that actually broke something.
lint is red on main itself
Reproduced locally on a clean detached worktree at origin/main = 506f4ab11a5d2a1b7a498e965c79d11e2fa63043, running the exact commands from test.yml:
$ ./scripts/check_file_size.sh
File size limit exceeded (2000 lines).
2010 crates/perry-runtime/src/timer.rs
$ python3 scripts/gc_store_site_inventory.py
GC store-site inventory failed; add nearby GC_STORE_AUDIT markers:
crates/perry-codegen/src/expr/property_set.rs:1475: raw generated heap/global store: blk.store(DOUBLE, &numeric_value, &field_ptr);
$ python3 scripts/raw_handle_debt.py
bare raw-handle reads: 996 (baseline 998)
per-module raw-handle rules: 2 violation(s)
crates/perry-runtime/src/json_tape.rs: 22 bare reads exceeds its ceiling of 21
crates/perry-runtime/src/object/spill.rs: 5 bare reads exceeds its ceiling of 3
All three are independent of any open PR. Note the global raw-handle count (996) is below its baseline (998) — it is the per-module rules that fail, which is exactly the failure mode raw_handle_debt_files.txt was designed to catch, so the gate is working correctly and the debt is real.
cargo-test fails identically on unrelated PRs
The same four tests fail on #8086 (73-file ShapeId change), #8090 (small typed-array fix), and #8087 (CI gates):
inprocess::tests::rs4gc_canonicalizes_construction_time_folds_before_root_liveness
native_emit::tests::native_construction_lowers_precise_roots_before_rs4gc
native_emit::tests::split_native_construction_lowers_precise_roots_before_rs4gc
native_emit::tests::split_native_construction_propagates_shadow_backend_to_workers
Byte-for-byte the same set on all three. These assert that two compilation arms produce byte-identical objects. Decoding the assertion dumps, the arms differ only in an embedded module/source name:
| test |
control arm |
native arm |
rs4gc_canonicalizes_… |
.file "constant_fold_text" |
.file "constant_fold_native" |
native_construction_… |
ELF STT_FILE = perry_llvm_7386555fbfde02f7.ll |
ELF STT_FILE = perry_native_module |
The generated code, stack maps, and PGCM payloads appear identical; the delta is the name each arm records for its translation unit. compile_ll_to_object routes through a scratch perry_llvm_<hash>.ll, while the in-process native arm names its module perry_native_module.
This is consistent with the platform split: both ELF arms of native-roots-rs4gc fail, while macOS/Mach-O and Windows/PE pass — Mach-O and PE do not carry an STT_FILE-style source-name symbol, so the difference is invisible there.
I have not bisected which change introduced this, and I have not confirmed it on a pristine main build (it does not reproduce on macOS, which is the only host I measured on). What is established is that it is not caused by any of the three PRs above.
Also red across the same unrelated PRs
Not diagnosed here, listed so the scope is not understated — every one of these is red on both #8086 and #8090:
gc-stress, ext-link, compiler-output-regression, e2e-scoped, gc-native-roots-complete, gc-root-dominance-statepoints, windows-arm64-build, Warnings (host-compatible), Warnings (product), and both ELF native-roots-rs4gc arms.
The last run of test.yml to conclude success on any branch was 2026-07-24.
Why this is worth fixing before more merges
A required-and-always-red context is strictly worse than no context: it is indistinguishable from a gate that is doing its job, it forces bypass as the normal path, and the bypass is what lands the next real regression. #6925's PERRY_PTR_SHAPE_LOCALS=0 regression landed visibly red and survived three merges for exactly this reason.
Suggested split
- Land the three
lint fixes against main directly — timer.rs is 10 lines over the cap, property_set.rs needs one GC_STORE_AUDIT marker, and json_tape.rs/object/spill.rs each need one converted pair (which also lowers their ceilings, per the file's own "lower a ceiling whenever you convert a pair" rule).
- Decide whether the four byte-identity tests should compare normalized objects (masking the translation-unit name) or whether both arms should name the module identically. A byte-identity assertion whose only observed delta is a filename is testing the filename.
- Triage the remaining red jobs separately; several may share the ELF/
STT_FILE root cause.
Refs #7737 (gate promotion), #8085 (gate freshness).
Summary
Two required status contexts,
lintandcargo-test, currently fail for every pull request, including on trees that change nothing related to them.lintalso fails on a pristineorigin/maincheckout. While that holds, neither context can distinguish a good PR from a bad one, and every merge necessarily goes through admin bypass.This is the CLAUDE.md "★ four ways a gate can be unable to fail" pattern in its most expensive form: the jobs run, genuinely report failure, and are required — so the only way to land anything is to ignore them, which trains the team to ignore them for the PR that actually broke something.
lintis red onmainitselfReproduced locally on a clean detached worktree at
origin/main=506f4ab11a5d2a1b7a498e965c79d11e2fa63043, running the exact commands fromtest.yml:All three are independent of any open PR. Note the global raw-handle count (996) is below its baseline (998) — it is the per-module rules that fail, which is exactly the failure mode
raw_handle_debt_files.txtwas designed to catch, so the gate is working correctly and the debt is real.cargo-testfails identically on unrelated PRsThe same four tests fail on #8086 (73-file ShapeId change), #8090 (small typed-array fix), and #8087 (CI gates):
Byte-for-byte the same set on all three. These assert that two compilation arms produce byte-identical objects. Decoding the assertion dumps, the arms differ only in an embedded module/source name:
rs4gc_canonicalizes_….file "constant_fold_text".file "constant_fold_native"native_construction_…STT_FILE=perry_llvm_7386555fbfde02f7.llSTT_FILE=perry_native_moduleThe generated code, stack maps, and
PGCMpayloads appear identical; the delta is the name each arm records for its translation unit.compile_ll_to_objectroutes through a scratchperry_llvm_<hash>.ll, while the in-process native arm names its moduleperry_native_module.This is consistent with the platform split: both ELF arms of
native-roots-rs4gcfail, while macOS/Mach-O and Windows/PE pass — Mach-O and PE do not carry anSTT_FILE-style source-name symbol, so the difference is invisible there.I have not bisected which change introduced this, and I have not confirmed it on a pristine
mainbuild (it does not reproduce on macOS, which is the only host I measured on). What is established is that it is not caused by any of the three PRs above.Also red across the same unrelated PRs
Not diagnosed here, listed so the scope is not understated — every one of these is red on both #8086 and #8090:
gc-stress,ext-link,compiler-output-regression,e2e-scoped,gc-native-roots-complete,gc-root-dominance-statepoints,windows-arm64-build,Warnings (host-compatible),Warnings (product), and both ELFnative-roots-rs4gcarms.The last run of
test.ymlto concludesuccesson any branch was 2026-07-24.Why this is worth fixing before more merges
A required-and-always-red context is strictly worse than no context: it is indistinguishable from a gate that is doing its job, it forces bypass as the normal path, and the bypass is what lands the next real regression. #6925's
PERRY_PTR_SHAPE_LOCALS=0regression landed visibly red and survived three merges for exactly this reason.Suggested split
lintfixes againstmaindirectly —timer.rsis 10 lines over the cap,property_set.rsneeds oneGC_STORE_AUDITmarker, andjson_tape.rs/object/spill.rseach need one converted pair (which also lowers their ceilings, per the file's own "lower a ceiling whenever you convert a pair" rule).STT_FILEroot cause.Refs #7737 (gate promotion), #8085 (gate freshness).