Repository navigation
fix(ci): skip storyboards on draft PRs and cancel superseded scans - #8225
Conversation
The org's GitHub-hosted runners were pinned at the 60-concurrent-job cap from 09:24 to 12:21 UTC on 2026-10-15. A median PR push queues about 48 jobs and 293 runner-minutes. Training Agent Storyboards is 49% of the repo's runner-minutes, about 22 jobs and 200+ minutes per push. - training-agent-storyboards.yml: skip all jobs on draft PRs and add ready_for_review so the full matrix runs when a draft is marked ready. The workflow is not a required check. Draft runs used about 850 runner-minutes on 2026-10-15. - codeql.yml, semgrep.yml, broken-links.yml, migration-smoke-test.yml: cancel a PR's superseded run on a new push. Non-PR runs get a unique group (run_id), so main, schedule, and workflow_run runs are never cancelled or evicted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated paths require human/CODEOWNERS approval.
This PR modifies five files under .github/workflows/**, which are under a hard, path-based approval gate (gated_paths: true). The current review_decision is REVIEW_REQUIRED, not APPROVED, so per decision-table row 2 the outcome must be escalate.
The diff itself is clean: no Critical/High/Medium findings. Concurrency blocks added to broken-links, codeql, migration-smoke-test, and semgrep correctly cancel only superseded PR runs while leaving push/schedule/workflow_run runs with unique groups; the training-agent-storyboards draft-skip uses the correct non-blocking job-level if pattern with ready_for_review coverage and a matching test; the patch changeset is in scope. Nothing blocks on the merits.
Escalation reasons
- Workflow files under
.github/workflows/**are gated;review_decisionisREVIEW_REQUIRED. Human/CODEOWNERS approval is required before merge:- .github/workflows/broken-links.yml
- .github/workflows/codeql.yml
- .github/workflows/migration-smoke-test.yml
- .github/workflows/semgrep.yml
- .github/workflows/training-agent-storyboards.yml
Why human review
- Gated paths: .github/workflows/** files (broken-links.yml, codeql.yml, migration-smoke-test.yml, semgrep.yml, training-agent-storyboards.yml) are under a hard approval gate and review_decision is REVIEW_REQUIRED — human/CODEOWNERS approval required before merge.
- This PR touches a path under a hard, non-overridable approval gate (.github/workflows/broken-links.yml (modified) matches
.github/workflows/**; .github/workflows/codeql.yml (modified) matches.github/workflows/**; .github/workflows/migration-smoke-test.yml (modified) matches.github/workflows/**; .github/workflows/semgrep.yml (modified) matches.github/workflows/**; .github/workflows/training-agent-storyboards.yml (modified) matches.github/workflows/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
Diagnosis (2026-10-15)
The backlog was caused by runner capacity, not a stuck workflow.
Org-wide hosted concurrency hit the cap.
ubuntu-latestjobs across adcp, adcp-client, adcp-client-python, adcp-go and actions gives 58 to 60 from 09:24 to 12:21 UTC, never above 60.adcp demand outran the cap.
Per PR push: p50 48 jobs and 293 runner-minutes, p90 60 jobs and 370 runner-minutes. One push alone can nearly fill the org's 60 slots.
Where today's 12,002 runner-minutes went:
Within storyboards, the 8 sales orchestrators average 16 minutes each, and 13 tenant jobs average 6 minutes.
Waste that was already low:
push+pull_requesttriggers don't double-run, because PR branches don't match thepushbranch filters.Change
training-agent-storyboards.ymlgithub.event.pull_request.draft != true).ready_for_reviewis added to the PR trigger types, so the full matrix runs when a draft is marked ready. Push runs are unchanged.codeql.yml,semgrep.yml,broken-links.yml,migration-smoke-test.ymlconcurrencythat cancels a PR's superseded run. Non-PR runs (push, schedule, workflow_run) each get a unique group (github.run_id), so main-branch analyses are never cancelled or evicted from a pending slot..changeset/skip-storyboards-on-draft-prs.mdcheck-changeset-protocol-scope.cjsscopestraining-agent-storyboards.ymlas protocol, and CI-only storyboard changes have carried patch changesets before (#6788).Deliberately not changed
docs/as needing the full server suite.concurrencyadded. Changes toai-review.ymlare gated to human review by design, and its superseded waste was 7 minutes today.Capacity is the remaining bottleneck
These changes cut demand, but a burst of 30 or more non-draft pushes will still exceed 60 slots. This needs a decision outside this PR:
Companion PR: #8224 (IPR checks no longer serialize behind the runner queue).
Verification
npx vitest run --dir tests/ tests/ci-runner-demand-workflows.test.mjs: 6 passed. The test asserts the draft guard on every storyboard job, theready_for_reviewtrigger, and the PR-only cancel shape.actionlint1.7.12: clean on all five workflows.check-changeset-protocol-scope.cjsandchangesets status --since=origin/main.🤖 Generated with Claude Code