Skip to content

Restore branch protection and assert it on every PR - #207

Merged
MelbourneDeveloper merged 1 commit into
mainfrom
ci/restore-branch-protection
Aug 12, 2026
Merged

Restore branch protection and assert it on every PR#207
MelbourneDeveloper merged 1 commit into
mainfrom
ci/restore-branch-protection

Conversation

@MelbourneDeveloper

Copy link
Copy Markdown
Collaborator

What was wrong

Both branch rulesets were enforcement: disabled. main had no required status checks at all — any PR could merge red and nothing would stop it.

PR #190 (212 files, +60,766/−37,428) merged at 10:38 on 2026-08-12. Issues #202 (wasm corpus aborts Node's WASI host), #203 (all 8 lldb-dap E2E tests time out on Linux) and #204 (website E2E flakes red) were filed at 10:09–10:10 — 29 minutes earlier. The failures weren't missed; they were written down and merged past. The websocket showstoppers #192#197 were filed the previous evening.

Two structural traps kept the gates off

Phantom context. Ruleset 7726557 required a check named "CI". No job reports that name — check runs are named by job name:, not by workflow. Enabling it would hang every PR pending forever, so the reachable fix under pressure is to switch the ruleset off. Its required_status_checks rule is dropped; it now carries the PR requirement (squash-only merges, thread resolution) and ruleset 6154907 owns the checks.

Path-filtered required job. ci-windows.yml skipped website-only PRs via on: paths-ignore:, which cannot be a required check: a filtered-out run never reports, and a required check that never reports blocks the merge forever. Its own comment said as much and concluded "so it isn't required". Converted to job-level if: skipping — which reports skipped, and a skipped check counts as passing — so windows-core can now be required.

State now

Both rulesets active, no bypass actors (applies to admins too), strict up-to-date policy, and six required checks:

Check Was
Detect changed areas not required
Test, Format, Build & Validate the only required check — and unenforced
Rust Compiler (fmt, clippy, test, corpus) not required
WebAssembly target (wasm32-wasip1) advisory by design — how #202 landed unopposed
Website E2E (Playwright) not required
Windows Core Build & Smoke Test not required, and not requirable

The part that stops it recurring

Branch protection lives in GitHub's settings, not in this tree, so it drifts silently and by definition no test covers it. scripts/verify-branch-protection.mjs is that test. It runs in the changes job — the one required job that never skips — and fails on:

  • a ruleset that isn't active, or that has bypass actors
  • drift in either direction between the pinned list and the live ruleset
  • a required context matching no job name: (the phantom trap)
  • a required job whose workflow path-filters at the on: level (the deadlock trap)

Verified against the real broken state rather than assumed: fed the exact 2026-08-12 configuration, it reports every fault, phantom "CI" included. Fed the pre-fix ci-windows.yml, it reports the path-filter deadlock.

Stale comments asserting these jobs were unrequired are corrected in place, and CLAUDE.md gains the rule this violated: a gate you can turn off is not a gate, "advisory" means deleted, and an open issue about a red check is a blocker rather than a footnote.

Not covered here

The failures themselves are still open — #202, #203, #204, the websocket showstoppers #192#197, and the effects umbrella #200. This PR only ensures the next one can't merge past them.

Both branch rulesets were `enforcement: disabled`. `main` had no required
status checks at all — PR #190 (212 files, +60766/-37428) merged green 29
minutes after its own CI failures were filed as issues #202, #203 and #204.

Two structural traps kept the gates off, and both are now checked:

Phantom context. Ruleset 7726557 required a check named "CI". No job reports
that name, so enabling it would hang every PR pending forever. The reachable
fix under pressure is to switch the ruleset off, which is what happened. Its
required_status_checks rule is dropped; it now carries the PR requirement
(squash-only, thread resolution) and ruleset 6154907 owns the checks.

Path-filtered required job. ci-windows.yml skipped via `on: paths-ignore:`,
which cannot be a required check: a filtered-out run never reports, and a
required check that never reports blocks the merge forever. Converted to
job-level `if:` skipping, which reports "skipped" and counts as passing, so
windows-core can now be required.

Both rulesets are active, with no bypass actors, and six required checks:
Detect changed areas, Test/Format/Build & Validate, Rust Compiler, WebAssembly
target, Website E2E, Windows Core. The wasm corpus differential was advisory
by design — that is how a wasm-only miscompile (#202) could land unopposed.

scripts/verify-branch-protection.mjs pins that list and runs in the `changes`
job, the one required job that never skips. It fails on a disabled ruleset, a
bypass actor, drift in either direction between the list and the ruleset, a
context matching no job name, and a required job its workflow path-filters.
Verified against the real broken state: it reports every one.

Stale comments claiming these jobs are unrequired are corrected, and CLAUDE.md
gains the rule this violated — a gate you can turn off is not a gate.
@MelbourneDeveloper
MelbourneDeveloper enabled auto-merge (squash) August 12, 2026 11:22
@MelbourneDeveloper
MelbourneDeveloper merged commit a57673e into main Aug 12, 2026
7 checks passed
@MelbourneDeveloper
MelbourneDeveloper deleted the ci/restore-branch-protection branch August 12, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant