Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/build-paper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ on:
paths:
- 'docs/WHITEPAPER/**'
pull_request:
branches: [ main, master ]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
paths:
- 'docs/WHITEPAPER/**'

Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/catalog-count-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ name: Catalog Count Invariant (CI-01)

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
paths:
- "specs/numeric/formats_catalog.t27"
- "tools/gen_formats_catalog.py"
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/check-now-freshness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ name: Check Now Freshness

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.

jobs:
check:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/coq-kernel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ on:
- 'coq/**'
- '.github/workflows/coq-kernel.yml'
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
paths:
- 'coq/**'
- '.github/workflows/coq-kernel.yml'
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/emit-bitexact-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ name: Emit Bit-Exact Gate (CI-02)

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
paths:
# The four backends this gate proves equivalent all live in ONE file,
# bootstrap/src/compiler.rs -- gen_zig:3437, gen_verilog:6741, gen_c:10522,
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/fpga-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ name: FPGA E2E Build

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
paths:
- 'specs/fpga/**'
- 'bootstrap/**'
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/gate-topology.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Gate Topology

# Checks the gates themselves rather than the code they guard.
#
# A gate with `branches: [master]` under `pull_request` does not run when a PR
# targets any other base. On a stacked PR every such gate is absent and
# `gh pr checks` prints a green list -- the green of a gate that never fired.
# Observed in this repository on 2026-08-15 on three gates at once.
#
# This workflow deliberately carries NO `branches:` filter, since a branch filter
# here would reproduce exactly the defect it exists to detect.

on:
pull_request:
push:
branches: [master]

jobs:
gate-topology:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Install pyyaml
run: python3 -m pip install --quiet pyyaml

- name: Merge-critical workflows must not filter pull_request by branch
run: python3 scripts/ci/check_pr_branch_filters.py
5 changes: 4 additions & 1 deletion .github/workflows/issue-gate.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Enforces L1 TRACEABILITY: No code merged without Closes #N
name: Issue Gate
on:
# `branches: [master]` removed on purpose: this is a required check, and with
# the filter it never ran on a stacked PR, so traceability was unenforced for
# exactly the PRs most likely to need it. See the same note in
# now-sync-gate.yml. An absent check is not a passing check.
pull_request_target:
types: [opened, edited, reopened, synchronize]
branches: [master]

permissions:
issues: read
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/notebook-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ name: NotebookLM Gate

on:
pull_request:
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
types: [opened, synchronize, reopened]
branches: [master, main]
push:
branches:
- '*'
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/now-sync-gate.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
name: NOW Sync Gate
on:
# No `branches:` filter on pull_request, deliberately. This gate is in the
# required-check set, and with the filter it did not run at all on a PR whose
# base was another branch -- `gh pr checks` then showed a green list on a
# stacked PR that no substantive gate had examined. A check that is absent is
# not a check that passed, and a reviewer reading the green list cannot tell
# the two apart. Measured on this repository: three gates (this one,
# issue-gate, seal-staleness-warn) were all silently skipped on stacked PRs.
#
# push keeps its filter: pushes to topic branches do not need the gate, only
# the protected branch does.
pull_request:
branches: [master]
push:
branches: [master]

Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/phi-loop-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ name: PHI Loop CI

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.

jobs:
phi-loop-check:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/schema-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ name: Schema Validation

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
push:
branches: [master]
workflow_dispatch:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/seal-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ name: Seal Coverage

on:
pull_request:
branches: [master]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.
push:
branches: [master]
workflow_dispatch:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/seal-staleness-warn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ name: Seal Staleness Warning
# rule: we never auto-reseal here; refreezing is an explicit human/PR step.

on:
# `branches: [master]` removed: this warning exists to tell a reviewer that the
# sealed numbers were certified against an older compiler, and a stacked PR
# that moves the seal is precisely the case where the reviewer needs to be
# told. The `paths:` filter stays -- it selects PRs that touch the seal, which
# is the intended scope; the base-branch filter selected nothing useful.
pull_request:
branches: [master]
paths:
- 'bootstrap/src/compiler.rs'
- 'bootstrap/stage0/FROZEN_HASH'
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
# No `branches:` filter on pull_request, deliberately. A branch filter makes
# this gate silent on any PR whose base is not listed -- a stacked PR then
# shows a green check list that a master-based PR would not get. Enforced by
# scripts/ci/check_pr_branch_filters.py. The `push` filter below, where one
# exists, is left alone: restricting post-merge runs is a cost decision.

jobs:
scan:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# NOW -- eleven gates were silent on stacked PRs (2026-08-21)

## ci: merge-critical workflows must not filter pull_request by branch (Closes #2167)

- **A gate written `on: pull_request: branches: [master]` does not run when the PR base is another branch.** On a stacked PR every such gate is absent and `gh pr checks` prints a green list -- the green of a gate that never fired. Observed here on three gates at once; those were patched, and this closes the rest
- **Measured, by parsing every workflow rather than reading names: eleven, not seven.** A previous work order said seven; that number came from a filtered `grep` and was wrong. Recorded rather than quietly replaced, because the seven was quoted downstream
- `paths:` filters are kept -- they select by what changed, not by target. `push:` branch filters are kept too: restricting post-merge runs is a cost decision, not a gating hole
- **The fix is a configuration test, not vigilance.** `scripts/ci/check_pr_branch_filters.py` lists merge-critical workflows explicitly, in code, reviewed as code. A test that inferred the list -- "everything named `*-gate`" -- would stop covering a gate the moment someone renamed it. Negative-tested: 11 violations before the patch, 0 after
- **Separately measured**: `auto-merge-ready-prs.yml` does not parse as YAML, so GitHub cannot load it and it does not run. Left untouched on purpose -- auto-merge is disabled by policy, and repairing the file would restore an automation that must not run. The test reports it as a warning, since a gate that lands red and stays red for a reason nobody may fix teaches everyone to ignore red
- **`schema-validation.yml` resolved against master, not taken verbatim.** Master had independently added `push:` and `workflow_dispatch:` triggers this branch never saw; applying the branch's version wholesale would have deleted both while removing the `branches:` filter. Only the `branches:` line was dropped, so all three triggers survive -- verified by parsing the merged YAML, and `check_pr_branch_filters.py` reports CLEAN on the result
- Entry migrated from `docs/NOW.md` to `docs/now/` (the layout #2298 introduced); the original entry was dated 2026-08-15
Loading
Loading