Skip to content

ci: parity and lint are required checks that a docs-only PR satisfies by skipping #469

Description

@ivndev001

Steps to reproduce

  1. Open a PR that touches no Ruby paths — .maintainer.yml alone, or a single README.md edit.
  2. Wait for checks to settle.
  3. gh pr view <n> --repo developerz-ai/wurk --json mergeStateStatus,statusCheckRollup

Observed on PR #468 (touches only .maintainer.yml): mergeStateStatus: CLEAN, with parity (oracle) and lint (rubocop) both reporting SKIPPED. Same on runs 33425640296 (PR #464, README-only) and 33426422088 (PR #465).

Expected

parity (oracle) and lint (rubocop) became required checks on the main-protection ruleset on 2026-09-01. A required check should be a gate that ran.

Actual

Both gate at JOB level:

  • .github/workflows/test.yml, job parity (name: parity (oracle)):
    if: github.event_name != 'pull_request' || needs.detect.outputs.ruby == 'true'
  • .github/workflows/test.yml, job lint (name: lint (rubocop)): the same if:

A job-level if: that evaluates false reports the check as skipped, and GitHub treats a skipped required check as satisfying the requirement. So a PR touching only paths outside the ruby filter reaches CLEAN having run neither of these two required checks.

The test job in the same file already solves this, and its own comment says why:

# Gated per STEP, not per job, so this job always reports a status even on
# a docs-only PR: a job-level `if:` reports "skipped", and anything that
# later marks this check required would park such a PR on "Expected —
# waiting for status" forever. On an irrelevant change it just does nothing.
RUN: ${{ github.event_name != 'pull_request' || needs.detect.outputs.ruby == 'true' }}

That comment predicted a permanent deadlock as the hazard. The real behaviour is the opposite and worse: no deadlock, and no gate either.

The exposure is not theoretical for .maintainer.yml specifically — it is the file that governs the maintainer bot's own merge posture, no check covers it, and it is exactly the kind of change that now merges with zero checks having executed.

Version

origin/main at 8f7232d.

Suggested fix

Convert parity and lint to the test job's per-step pattern: drop the job-level if:, set a RUN env var from the same expression, and gate each step on it. Both jobs then always report a real status, and on an irrelevant change they do nothing and report success honestly.

Worth deciding in the same pass: whether spec-docs and frontend should follow, if either is ever made required.

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

    area/cibugSomething isn't workingpriority/p1High — drop-in correctness / common pathsize/1h~1 hour — small, 2-5 files

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions