Skip to content

feat(pr-status): tell a queued check apart from a running one - #139

Merged
CybotTM merged 2 commits into
mainfrom
feat/distinguish-queued-from-running
Aug 5, 2026
Merged

feat(pr-status): tell a queued check apart from a running one#139
CybotTM merged 2 commits into
mainfrom
feat/distinguish-queued-from-running

Conversation

@CybotTM

@CybotTM CybotTM commented Aug 5, 2026

Copy link
Copy Markdown
Member

GitHub reports queued and in_progress as different check states. pr-status.sh collapsed both into "pending" and answered required check(s) still running — which reads as CI being slow when in truth no runner has picked anything up. The two situations have opposite answers.

Why the distinction decides something

A merge queue drops an entry whose required check does not report within check_response_timeout_minutes, and that clock covers the wait for a runner, not just the run. references/pull-request-workflow.md already carried the warning — "Do not enqueue into a busy runner pool", including the detail that a dropped entry does not cancel its runs so each retry makes it worse. But the tool an operator actually follows had no way to tell a busy pool from a slow one, so the warning could not be acted on.

Observed today on netresearch/t3x-nr-llm#594: both merge-queue entries had CI at status=queued, never started, and the entry was discarded having executed nothing. Meanwhile 44 runs sat queued across 14 repositories with zero running. pr-status reported "still running" throughout.

The change

  • QUEUED is classified separately from IN_PROGRESS; pending downstream keeps its meaning of "not finished".
  • New verdict await-capacity when a required check is queued while nothing at all is running, naming the checks and the counts.
  • The checks line now reads N pending (X running, Y queued).
  • checks.queued, checks.running and checks.queued_required are exposed in --json.

Deliberately not included: the limit

I looked for it rather than assuming:

$ gh api /orgs/netresearch/actions/hosted-runners/limits
{"message":"GitHub hosted runners are not supported for this organization","status":"404"}
$ gh api /orgs/netresearch --jq '.plan.name'
free

The endpoint covers larger runners only, and the per-plan ceiling for standard runners exists in documentation, not in the API. So the check observes state — required checks queued with zero running is sufficient on its own — instead of comparing against a number it cannot read.

Verification

shellcheck and bash -n clean. Behaviour unchanged on three live PRs (triage-ci, fix-ci, and the merge-queue branch on #594 which still takes precedence, as it should).

The new branch could not be exercised against live data: the backlog drained while this was being written, so no PR currently has a queued required check. The classification and the branch condition are shown on synthetic input instead, which is weaker evidence and worth saying plainly:

$ jq -nc '[{status:"QUEUED"},{status:"IN_PROGRESS"},{status:"COMPLETED",conclusion:"SUCCESS"}] | map(...)'
[{"state":"QUEUED"},{"state":"PENDING"},{"state":"PASS"}]

# required queued, nothing running
await-capacity — required check(s) queued and not started: ci / CI — 6 queued, 0 running
# something running
wait — required check(s) still running

GitHub reports queued and in_progress as different states; pr-status
collapsed both into pending and said 'required check(s) still running'.
That reads as CI being slow when in truth no runner has picked anything
up, and the two situations have opposite answers.

The distinction decides whether enqueueing is safe. A merge queue drops
an entry whose required check does not report within
check_response_timeout_minutes, and that clock covers the wait for a
runner — references/pull-request-workflow.md already warned not to
enqueue into a busy pool, but the tool operators actually follow could
not tell a busy pool from a slow one. Observed today on
netresearch/t3x-nr-llm#594: both queue entries had CI at status=queued,
never started, and the entry was discarded having executed nothing.

The new verdict await-capacity fires when a required check is queued
while nothing is running. The checks line now reads
'N pending (X running, Y queued)'.

The limit itself stays out of it:
/orgs/{org}/actions/hosted-runners/limits answers 404 outside the
larger-runner product and the per-plan ceiling is documentation only, so
the check observes state rather than comparing against a number it
cannot read.

Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
Copilot AI lite review requested due to automatic review settings August 5, 2026 09:50
@github-actions github-actions Bot added documentation Improvements or additions to documentation skill evals labels Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…oblem

Review of the previous commit found a false positive it would produce on
every push: for the first seconds after a push all checks are queued and
none is running, which is normal and says nothing about runner capacity.
The condition as written answered await-capacity immediately, telling
the reader no runner had picked anything up when the checks were simply
new.

The verdict now also requires the oldest queued REQUIRED check to have
sat there for at least five minutes, and reports the age. Five is not
arbitrary: it is check_response_timeout_minutes, the tolerance the merge
queue itself applies before dropping an entry, so the warning starts
exactly where the risk it warns about starts.

Also: the comment that carried this explanation contained an apostrophe,
which ended the single-quoted shell string holding the whole jq program.
shellcheck caught it (SC1011). Prose inside that string stays
apostrophe-free, and the comment now says so.

Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
@CybotTM

CybotTM commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

siehe oben

@sonarqubecloud

sonarqubecloud Bot commented Aug 5, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CybotTM
CybotTM merged commit e0dbdcb into main Aug 5, 2026
21 of 22 checks passed
@CybotTM
CybotTM deleted the feat/distinguish-queued-from-running branch August 5, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation evals skill

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants