Skip to content

c-unit.yml: required checks run-linux/run-linux-serial are skipped on every unlabelled PR by a needs-chain cascade #605

Open

Description

@zackees

Found by WF-004, which was written from the same defect in zackees/clud#1805.

The defect

build:
  if: github.event_name == 'workflow_dispatch'
      || (github.event_name == 'pull_request' && (contains(labels, 'ci-test') || ...))

run-linux:
  needs: ['resolve-candidate', 'build', 'build-bun-objects']   # no if: at all

run-linux-serial:
  needs: ['resolve-candidate', 'build']                      # no if: at all

In GitHub Actions, a SKIPPED needs: skips the dependent regardless of its own if: — and here the dependents have no if: at all. So build being label-gated propagates straight through.

Why this one matters more than the others

Branch protection on main requires:

"run-linux", "run-linux-serial", "run-windows", "ctest (windows-latest)", ...

run-linux and run-linux-serial are required checks that skip on every PR without the ci-test label. A skipped required check is reported by GitHub as neither success nor failure, so the practical outcome depends on how the merge queue/branch protection treats a permanently-skipped required context — commonly a PR that cannot be merged, or one that sits forever looking almost-green.

This is live right now: the only open PR, #604, carries no labels, so on it build skips and both required checks skip with it.

The same shape, more instances

memory-gate        needs memory-gate-decide (pull_request only)
                   -> skipped on every push to main instead
run-windows-native needs build-windows-native
test-binaries      needs build-linux / build-cross / build-win-gnu
reproduce          needs build
run-windows        needs build-windows-gnu / -msvc / build-rust-*

Suggested fix

If these jobs should run on every PR, the dependency cannot be the label-gated builder — or the dependents need always() && !cancelled() with their own condition. If they are genuinely meant to run only under ci-test, then they should not be required status checks, since a required check must have an answer on every PR.

That is a policy decision (which of ci-test/unlabelled is the supported path), so this is filed rather than fixed.

Note on scope

WF-004 reports 9 findings across this repository and 14 across the audited fleet (clud installer-check.yml x4, soldr macos-recovery-replay.yml x1). It is needs_review rather than a violation for exactly this reason: whether a dependent genuinely must run when its dependency skips is the repository's judgement. Here that judgement is forced by branch protection, which is why it is worth acting on.

Activity

  1. zackees commented on Oct 5, 2026

    @zackees
    OwnerAuthor

    Triaged the full WF-004 sweep across 8 fleet repositories (23 findings) to put this one in context. Most are benign, and needs_review is why:

    repo findings verdict
    zackees/mimalloc-pprof 9 actionable — required checks (run-linux, run-linux-serial, run-windows)
    zackees/template-python-rust-cmd 6 actionable — fast, the PR quick gate
    zackees/clud 4 actionable — installer-check.yml chain
    zackees/soldr 1 macos-recovery-replay.yml — replay-only, low impact
    zackees/reld 2 benign — see below
    zackees/zccache 1 benign
    zackees/wild, zackees/kernal-api, zackees/bosn 0 clean

    Why the reld and zccache ones are benign, since "it depends on a skipped job" is not by itself a defect:

    • zccache perf-guard: the dependent's condition is identical to its dependency's (github.ref == 'refs/heads/main' || workflow_dispatch). It can never skip when its dependency ran, or run when it skipped — the cascade has nothing to do.
    • reld release-site: deploy has no if:, but the workflow only triggers on workflow_dispatch / workflow_run, which is exactly when build runs. The gating is uniform at the workflow level rather than the job level.
    • reld benchmark-stats: benchmark and its driver are both schedule-gated in the same file.

    This is precisely why WF-004 is needs_review and not a violation: "depends on a job that can skip" is common and usually fine. It only bites when the restricting condition differs between the dependency and its dependent — which is what makes this repository's instance serious (a label-gated builder feeding required checks with no if:) and the other three vacuous.

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