Skip to content

verify-release-intent: opened-before-labeled race produces a spurious failing check run #93

Description

@cratis-direct

What's happening

verify-release-intent.yml correctly implements its label-extraction logic — this is not a bug in the jq filtering. But there's a race condition in how consuming repos trigger it that produces a confusing, spurious failing check run whenever a pull request is opened and then labeled a few seconds later (a very common flow: gh pr create --label patch, or a human opening a PR and immediately clicking a label).

Concrete example (Cratis/Templates PR #36)

Every repo's thin caller (verify-semver-label.yml) triggers on:

on:
  pull_request:
    types: [opened, reopened, synchronize, labeled, unlabeled]

For PR #36 (fix/26-atomic-publication):

  • 2026-09-06T09:08:12Z — PR opened (no labels yet) → run 34023786118 starts, evaluates LABELS: [], fails with "This pull request states no release intent."
  • 2026-09-06T09:08:16Zpatch label added → run 34023791826 starts (correctly sees patch), succeeds.

The concurrency: cancel-in-progress: true group (${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}) is supposed to cancel the stale "opened" run once the "labeled" run starts for the same PR, but the job body is a few lines of jq/bash that finishes in well under a second — faster than GitHub can cancel it. So instead of the older run being cleanly superseded (which does happen sometimes — see run 33147269338 on PR carrying docs/discoverability, which shows cancelled), it completes first and posts a failure.

The result: the commit ends up with both a failure and a success entry for the same check name (verify / verify) in its status-check rollup. It doesn't block merging (the latest run for the SHA is what GitHub's merge gate honors), but it's confusing — a red X shows up in the PR's check history for a run that already reflects stale, pre-label state, and it can trigger unnecessary "why did this fail?" investigation (as it did here).

This isn't unique to Cratis/Templates — every repo that adopted the reusable workflow copies the same types: [...] trigger list (checked Chronicle, Arc, Fundamentals, Components — all identical), so all of them see this whenever a PR is opened before it's labeled.

Possible directions (not prescribing a fix — this is a judgment call for the team that owns the gate's UX)

  • Drop opened from the trigger types, since it almost always precedes a deliberate label choice; labeled/unlabeled/synchronize would still guarantee the check reruns whenever the label state or code actually changes. Trade-off: a PR that's opened and genuinely never labeled would show as "expected"/pending rather than an explicit failing message telling the author what to do.
  • Or accept this as a known, non-blocking cosmetic rough edge, since it never actually blocks a merge.

Evidence

Filed after investigating Cratis/Templates#37 (a workflow-run failure report) — no code fix was made in Cratis/Templates, since its thin caller has no logic to fix and correctly delegates to this reusable workflow.

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions