Skip to content

apply-branch-gates: a gate workflow no PR can trigger still derives a required context #1040

Description

@hyperpolymath

The gap

scripts/apply-branch-gates.sh can derive a required status check context from a workflow that
no pull request can ever trigger, and no existing control catches it.

Measured on metadatastician/paint-type, 2026-09-23:

  • codeql.yml's trigger on main is verbatim on: / workflow_dispatch: — dispatch-only.
  • Its last five runs on main are nonetheless all event: push, all conclusion: failure
    stale artefacts of a retired trigger.
  • The applier selects the newest run (35782158972) and derives its sole job,
    analyze (actions, none), as a required context.
  • A required context no PR can emit permanently blocks every future merge on that repo.

Why neither existing control covers it

control what it keys on why it misses this
derive_failed run readability — a run returning zero jobs the run reads fine; it is the workflow that is unreachable
--require-green N run greenness it DROPS non-green contexts rather than refusing. It masked this case only by the coincidence that the workflow is currently failing. Had it been manually dispatched green, --require-green would have admitted a permanently-unsatisfiable required check

Greenness and readability are not PR-reachability. They are three different questions.

#1038 cures the one measured instance by adding codeql.yml to never_required_workflows. That
is a denylist, not a check: the next dispatch-only or tag-only gate workflow reintroduces the
same failure mode silently.

Acceptance criteria

  1. The applier reads each gate workflow's on: block at the repository's default branch and
    classifies it as PR-reachable or not. A workflow is PR-reachable iff its on: block contains
    a pull_request (or pull_request_target) trigger — in either the mapping form
    (on:\n pull_request:) or the sequence form (on: [push, pull_request]).
  2. A gate workflow that is not PR-reachable is REFUSED, not dropped — the applier must
    not write a partial gate silently. The refusal names the workflow and the reason, in the same
    derive_failed-style detail field.
  3. Proven by a matched-pair test in scripts/tests/branch-gates-apply-test.sh: a
    dispatch-only workflow whose newest run is green is REFUSED, while the same fixture under
    --require-green alone would have admitted it. The pair is what proves the new control is
    not the old one under a different name.
  4. A mutant that neuters the reachability refusal must kill that case, guarded by the
    suite's existing cmp -s + bash -n pattern.
  5. Once landed, codeql.yml can be removed from never_required_workflows, restoring the
    context on any repo where it genuinely is PR-reachable. That removal is the closing step of
    this issue, and it is what reverses feat(gates): create branch gates where none exist, and harden three policies #1038's deliberate estate-wide scope.

Scope note

#1038's never_required_workflows entry is estate-wide while its evidence is paint-type's. It is
consistent with existing policy — never_required_contexts already carries
"CodeQL (default setup)", so CodeQL is enforced estate-wide by EstateBranching's
code_scanning rule rather than by any required status context — but a repo whose
codeql.yml is PR-reachable loses that context until this issue closes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YSq3UodR3CjsuAK5yoTzHF

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions