fix(workflows): add workflow_dispatch to pr-labels-ci.yml to prime workflow_run listener#24
Conversation
…rkflow_run listener yt-dont-recommend's pr-labels-ci.yml has never received a workflow_run event since PR #19 merged. Every run in its history is event=push with conclusion=failure (startup). The GitHub API also reports the workflow's name as the file path rather than the declared "PR Label Automation (CI)" — consistent with the file never having been successfully parsed into the workflow catalogue. This is why every PR since #19 has stuck at "Awaiting CI" and needed the Dev Active toggle workaround to promote to Ready for QA — the on-ci-pass job is never dispatched. Fix: add a workflow_dispatch trigger. When the maintainer runs the workflow manually once (Actions -> Run workflow), the existing if: guards (which all reference github.event.workflow_run.*) don't match, so both jobs skip cleanly — producing a successful run that registers the file in GitHub's workflow catalogue. After that, the workflow_run dispatcher fires on CI completions and the promotion works automatically. Cascade: mcp-clipboard's pr-labels-ci.yml is already registered and working correctly, so it doesn't need this fix to function — but propagating workflow_dispatch there preserves the verbatim-from- mcp-clipboard contract and gives the same debugging handle. Noted in the PR body for the maintainer to decide. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
cmeans
left a comment
There was a problem hiding this comment.
[QA] Review — zero findings, Ready for QA Signoff.
Verified in this session
| Check | Result |
|---|---|
YAML parse of pr-labels-ci.yml |
Clean; on: block now carries both workflow_dispatch: (null value, standard GHA shape) and the existing workflow_run: trigger. |
Diff vs cmeans/mcp-clipboard/.github/workflows/pr-labels-ci.yml |
Only adds: the 15-line comment block (lines 14–28) explaining seeding + debugging purposes, and the workflow_dispatch: line. Zero changes to any job, if: guard, env, or shell. Exactly what the PR body claims. |
pytest tests/ |
259/259 pass (non-code change). |
ruff check src/ tests/ |
All checks passed! |
Diagnosis independently confirmed via gh api
The repo's actions/workflows endpoint confirms the listener-registration failure exactly as Dev described:
pr-labels-ci.ymlreportsname = ".github/workflows/pr-labels-ci.yml"(file path). Its siblings correctly report declared names —pr-labels.yml→PR Label Automation,qa-gate.yml→QA Gate. The name-is-path symptom is diagnostic of a never-successfully-parsed workflow.actions/workflows/pr-labels-ci.yml/runs—total_count=10; every entry isevent=push conclusion=failure. Zeroevent=workflow_runruns since the file landed on main. The listener has genuinely never fired.
That matches Dev's claim verbatim and validates the workflow_dispatch prime as the correct fix.
if: guard behaviour on workflow_dispatch
Spot-checked: both jobs' if: conditions reference github.event.workflow_run.conclusion and github.event.workflow_run.event. On a workflow_dispatch event these context fields don't exist, so the == 'success' / == 'failure' comparisons evaluate to false and the jobs skip cleanly. The manual-run will be a successful-no-op exactly as Dev describes — no accidental logic execution.
Verdict
Applying Ready for QA Signoff. Zero findings in scope.
Post-merge action (for you)
- Actions tab → PR Label Automation (CI) → Run workflow → branch
main→ Run workflow. Expect ~10s, both jobs skipped. - Confirm
actions/workflowsnow reportsname = "PR Label Automation (CI)"instead of the file path — that's the registration proof. - Next PR should auto-promote
Awaiting CI→Ready for QAon CI pass without theDev Activetoggle.
Cascade
Filed cmeans/mcp-clipboard#89 to propagate workflow_dispatch there once this one's merged and validated. Classified nice-to-have (not blocking anything in mcp-clipboard today — its listener is already registered). Preserves the verbatim-from-mcp-clipboard contract and gives the same manual-debugging handle.
…un context Attempting to seed the workflow via workflow_dispatch on main after PR #24 merged failed with: Failed to queue workflow run: Invalid Argument - failed to parse workflow: (Line: 55, Col: 14): An expression was expected, (Line: 111, Col: 14): An expression was expected Lines 55 and 111 are `run: |` in both jobs. The real problem is a few lines earlier: the step-level env: references `github.event.workflow_run.id` and `github.event.workflow_run.head_branch`, which are absent when the workflow is triggered via workflow_dispatch (or a validation push). GitHub evaluates step-level env: expressions at queue time — before the job-level `if:` has a chance to skip the job — so the missing context is fatal even though the logic would skip cleanly. This is also the likely explanation for the push-event startup failures in this workflow's run history: every push GitHub validates has been failing to resolve these env: expressions, which is what prevented the file from being registered in the workflow catalogue and made the workflow_run listener never fire. Fix: add `|| ''` null-coalesce fallbacks to both env: expressions. On workflow_run events (the happy path), the fallback is never exercised — behaviour is unchanged. On workflow_dispatch and push events, the env: assignments cleanly resolve to empty strings, the job-level `if:` fails as designed, and the job skips — producing a successful run that finally registers the file with GitHub. Cascade: cmeans/mcp-clipboard should pick up the same fallbacks. They don't exercise workflow_dispatch today, so the bug is latent there, but the guard is strictly more defensive and preserves the verbatim contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…actual bug) Root cause for the workflow_dispatch parse failures that defeated PRs #24, #25, #26, and #27: GitHub Actions substitutes '\${{ ... }}' expressions inside run: blocks *before* the shell sees them, including sequences inside shell comments. Three comments in this file contained the literal string '\${{ }}' (empty expression). GHA's queue-time parser tried to evaluate an empty expression and bailed with 'An expression was expected', always pointing at 'run: |' (col 14) because that's the parent scope. Diagnostic that confirmed this: the reported line numbers shifted between my earlier attempts (55/111 -> 53/126 after the jq refactor). The error position is file-structure-dependent; col 14 is always the '|' of 'run: |'. Meanwhile the literal '\${{ }}' was identical across every version of the file since the security-hardening cascade (mcp-clipboard#87), which is why every '|| X' fallback experiment missed — the fallbacks were on the wrong expressions. Fix: rewrite the three comments to describe the concept without the literal '\${{ }}' characters. Zero logic change. Why this only surfaced on workflow_dispatch (not on normal workflow_run firings): the normal workflow_run code path apparently tolerates empty expressions where the queue-time parser for workflow_dispatch does not. mcp-clipboard has the same latent bug — it just never tripped it because nobody dispatched manually. Cascade: the same fix needs to land on cmeans/mcp-clipboard's file to preserve verbatim parity and to unblock manual dispatch there as well. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…commend#24 (#93) ## Summary Restores template parity for `pr-labels-ci.yml` with `cmeans/yt-dont-recommend`, which diverged by adding a `workflow_dispatch:` trigger in PR #24 (needed over there to prime the `workflow_run` dispatcher after its fresh-repo cascade). The diff applied here is verbatim from that upstream PR. The new trigger has two purposes, documented inline in the file: 1. **Seeding** — in a fresh-repo cascade, the `workflow_run` dispatcher doesn't always register until the workflow has produced at least one non-startup-failure run. A manual dispatch produces a clean skipped run and primes the dispatcher. 2. **Debugging** — gives maintainers a manual "Run workflow" button from the Actions UI without having to piggyback on a real CI run. **No-op on existing PRs.** Both jobs' `if:` guards require `github.event.workflow_run.*`, which are absent on a `workflow_dispatch` event, so a manual run always skips cleanly. **Side benefit:** a manual dispatch now serves as direct confirmation that the queue-time parser accepts this file. Prior to PR #92 landing (removing the literal empty GHA expression from two shell comments), a manual dispatch here would have failed with "An expression was expected" — so this PR is the natural post-fix validation point. Closes #89. ## Test plan - [x] `yaml.safe_load` on the file — clean parse with both triggers present (verified locally; confirms both `workflow_dispatch:` and `workflow_run:` keys present). - [x] CI (unchanged) runs green. - [ ] Post-merge: Actions tab -> "PR Label Automation (CI)" -> "Run workflow" -> main. Expected: clean queue, both jobs skip via `if:` guards, run completes in a few seconds. This is the direct validation that PR #92's fix works at the queue-time parser level. - [ ] Subsequent PRs continue to auto-promote from `Awaiting CI` to `Ready for QA` as before (no regression on the `workflow_run` path). ## Related - Upstream template change: `cmeans/yt-dont-recommend#24` - Prerequisite on this repo: #92 (removed the literal empty GHA expression that would have made a manual dispatch fail) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: cmeans-claude-dev[bot] <3223881+cmeans-claude-dev[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…CI fix (#36) Pre-release audit against `git log v0.4.2..main` surfaced three gaps in the `[Unreleased]` section: - No entry for PR #19 (QA workflow + PR label state machine) — a major infrastructure addition precedented by v0.4.2's Ruff entry. - No entry for the #24-#28 `workflow_run` registration fix saga. - The coverage push entry did not call out the `# pragma: no cover` sweep, which is a hard-rule policy for the project. Adds an Added entry for #19, a Fixed entry for #24-#28, and tacks a sentence onto the existing coverage entry. No code changes. Co-authored-by: cmeans-claude-dev[bot] <3223881+cmeans-claude-dev[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Every PR opened on this repo since PR #19 merged has stuck at
Awaiting CIand needed theDev Activetoggle workaround to promote. This PR is the real fix.Diagnosis
pr-labels-ci.ymllanded on main via PR #19 (workflow introduction) on 2026-04-20 at 02:15 UTC. Since then, zeroevent=workflow_runruns have been dispatched to it. All three runs in its history areevent=pushwithconclusion=failure(startup failure on workflow files that don't declare apushtrigger — GitHub validates on every push that touches the repo).Corroborating symptom:
gh api repos/.../actions/workflows | jq '.workflows[]'reports the workflow'snameas.github/workflows/pr-labels-ci.yml(the file path), not the declared"PR Label Automation (CI)". That's consistent with the file never having been successfully parsed into the workflow catalogue. And the workflow_run dispatcher seems to route events by parsed metadata — so if the file isn't parsed, the listener doesn't receive dispatches.mcp-clipboard's version of the same file works fine. The difference is just history: mcp-clipboard's file has had successful
event=workflow_runruns since at least 2026-04-16, which registered it correctly.Fix
Add a
workflow_dispatch:trigger to theon:block ofpr-labels-ci.yml. Manually running the workflow once after merge produces a clean "successful skipped" run:workflow_dispatchsatisfies the workflow's trigger.if:guards that referencegithub.event.workflow_run.*. On aworkflow_dispatchevent, those fields don't exist, so the conditions evaluate to false and the jobs skip cleanly.workflow_rundispatches fire normally on CI completions.Nothing in the existing logic changes. The only functional surface added is the manual-run capability.
Post-merge action required
After merge, go to the repo's Actions tab → PR Label Automation (CI) → Run workflow → select
main→ Run workflow. Should complete in ~10 seconds with both jobs skipped. Next PR after that should auto-promoteAwaiting CI→Ready for QAon CI pass without theDev Activetoggle.I can run this via the API, but my bot token doesn't have
Actions: writepermission on this repo — last time we tested it returnedResource not accessible by integration. Either the maintainer runs it, or the App's permissions get updated (separate decision).Cascade
cmeans/mcp-clipboard'spr-labels-ci.ymlis already registered and working — it doesn't need this fix to function. However, propagatingworkflow_dispatchthere preserves the verbatim-from-mcp-clipboard contract and gives the same manual-debugging handle that's useful when investigating label automation issues.Recommendation: cascade to mcp-clipboard as a follow-up PR once this one's merged and validated. If you'd rather let yt-dont-recommend diverge intentionally (different history, different needs), that's also defensible — just note it.
Test plan (QA)
yaml.safe_loadon.github/workflows/pr-labels-ci.yml— clean parsecmeans/mcp-clipboard/.github/workflows/pr-labels-ci.yml— only difference should be the newworkflow_dispatch:line and the accompanying comment blockpytest tests//ruff check src/ tests/still green (non-code change)workflow_dispatchrun completes successfully with both jobs skippedReady for QAon CI success (noDev Activetoggle required)Caveat
This PR is itself affected by the same bug. Expect it to stick at
Awaiting CIafter CI passes — I'll still need to do theDev Activetoggle to promote it. The fix only takes effect on subsequent PRs after the post-merge seeding run.🤖 Generated with Claude Code