Skip to content

CI: a docs-only PR can never merge — required contexts never report under ci.yml's paths-ignore, and the merge queue that made that safe is off #1892

Description

@macanderson

Problem

A pull request that touches only prose is permanently BLOCKED. Not slow — unmergeable.

Branch protection requires three contexts:

$ gh api repos/macanderson/stella/branches/main/protection/required_status_checks --jq .contexts
["fmt + clippy + test", "cargo deny + cargo audit", "harbor_adapter + analyzer pytest"]

The first two come from ci.yml, which carries paths-ignore for website/**, docs/**, *.md and .github/ISSUE_TEMPLATE/**. A workflow skipped by a path filter reports nothing at all — unlike a job skipped by an if: condition, which reports skipped and satisfies branch protection. GitHub therefore waits forever for a check that will never arrive.

Live example: #1863, a two-line fix to AGENTS.md and CONTRIBUTING.md that unbreaks main's gate-parity failure. Every check it reports is green; mergeStateStatus is BLOCKED; the two ci.yml contexts are absent from its check list entirely. The fix for a red main cannot land because it is prose.

Why the design is not wrong, only unfinished

ci.yml's own comment states the assumption:

Note merge_group does NOT honor paths-ignore, so a docs-only PR that skips the Rust gate on pull_request still runs the full gate once queued; that is deliberate — the required check must report on the merged result.

That is correct and it requires the merge queue to be enabled. It is not (#1645 option 1, which needs admin). So the filter that was safe under a queue is, without one, a trap.

This also explains prose PRs that did merge: enforce_admins is off, so an admin can bypass. Everyone else waits.

Fix directions

  1. Enable the merge queue (Red PRs keep landing on main: enforce_admins is off and the pre-push gate is routinely --no-verify'd #1645). Restores the documented design exactly, fixes this and the BEHIND-deadlock class together. Needs admin.
  2. Move the filtering from the workflow into the jobs. Drop paths-ignore from the triggers; add a cheap changes job (dorny/paths-filter or a git diff step) and gate the expensive jobs with if: needs.changes.outputs.rust == 'true'. A skipped job does satisfy a required check, so the contexts always report and a prose PR still costs seconds. No admin needed.
  3. A same-name stub workflow on the inverse path filter. Standard practice, but a PR touching both prose and code then produces two check runs with the same name, which is confusing enough to be its own hazard. Least preferred.

Recommend (2) if the queue is not going to be enabled soon — it is self-contained, needs no repository settings, and keeps the cost saving that motivated the filter.

Verify

Open a PR touching only *.md. Today it sits BLOCKED with all reported checks green and the two ci.yml contexts missing. After the fix it either reports them as skipped (option 2) or runs them in the queue (option 1), and merges.

Constraints

Refs #1645, #1439, #1863, #1883

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Drop everything — broken or embarrassing for usersarea:ciGitHub Actions, release pipeline, packagingbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions