Observed repeatedly on #341 and written up only in a PR comment there, so filing it properly. It is a fourth mechanism, distinct from the three already in CLAUDE.md's "A PR fixing claude-code-review.yml (or claude.yml) itself can't self-verify before merge" section.
What happens
On a PR that touches any file under .github/workflows/, a workflow_dispatch-triggered review dies about 12 seconds in:
Attempt 1 failed: Workflow validation failed. The workflow file must exist and have identical content to the version on the repository's default branch. [...] This is expected when adding Claude Code workflows to new repositories or on PRs with workflow changes.
Action skipped due to workflow validation error.
The action then writes no execution output at all. upload-review-execution falls back to the temp path, finds nothing, and run-review-guard correctly reports:
::error::Claude review produced no execution output — treating as a failed review.
So claude-review fails, require-review fails, and the recorded cost is $0.0000.
Why the existing guards don't catch it
- It is not a stub review. gha#185's retry path needs an execution file to inspect; here there is none, so the retry isn't even eligible.
- It is not the
Skip self-review when the PR edits this workflow guard. That one compares against the CALLER's own review-workflow path (claude-review.yml in this repo), so a PR editing claude.yml, _selftest.yml, or any other workflow sails straight past it and into this failure.
- It is not the
@v2-lag gap. The tag's position is irrelevant; this is the action's own App-token exchange refusing.
The asymmetry that makes it confusing: the pull_request-triggered review on the same head passes validation and reviews normally. So the PR can hold a genuine, complete verdict while require-review is red from a dispatched run — and every subsequent dispatch re-reddens it.
Why it compounds
Dispatched reviews are exactly what claude.yml fires when someone mentions the bot on such a PR. On #341 that produced four dispatched runs, each failing validation, each also cancelling the pull_request run that could have passed — because they share the claude-review-<PR> concurrency group. Recovering meant re-running the pull_request run once nothing else was in flight.
Suggested fix
Detect this specific signature — action skipped for workflow validation, zero execution output — and have run-review-guard skip rather than fail, the way it already skips for quota exhaustion. A dispatched review that was never allowed to start is not a failed review, and reporting it as one trains readers to ignore a red require-review, which is the check's whole value.
Worth pairing with a log line naming the cause, since the current error message ("produced no execution output") describes the symptom and gives no hint that a workflow-file change is why.
Not urgent
No correctness or security impact; the pull_request-triggered review still works, and the failure is loud rather than silent. The cost is a red required check that has to be diagnosed by hand each time, plus the cancellation collateral above.
Observed repeatedly on #341 and written up only in a PR comment there, so filing it properly. It is a fourth mechanism, distinct from the three already in
CLAUDE.md's "A PR fixing claude-code-review.yml (or claude.yml) itself can't self-verify before merge" section.What happens
On a PR that touches any file under
.github/workflows/, aworkflow_dispatch-triggered review dies about 12 seconds in:The action then writes no execution output at all.
upload-review-executionfalls back to the temp path, finds nothing, andrun-review-guardcorrectly reports:So
claude-reviewfails,require-reviewfails, and the recorded cost is$0.0000.Why the existing guards don't catch it
Skip self-review when the PR edits this workflowguard. That one compares against the CALLER's own review-workflow path (claude-review.ymlin this repo), so a PR editingclaude.yml,_selftest.yml, or any other workflow sails straight past it and into this failure.@v2-lag gap. The tag's position is irrelevant; this is the action's own App-token exchange refusing.The asymmetry that makes it confusing: the
pull_request-triggered review on the same head passes validation and reviews normally. So the PR can hold a genuine, complete verdict whilerequire-reviewis red from a dispatched run — and every subsequent dispatch re-reddens it.Why it compounds
Dispatched reviews are exactly what
claude.ymlfires when someone mentions the bot on such a PR. On #341 that produced four dispatched runs, each failing validation, each also cancelling thepull_requestrun that could have passed — because they share theclaude-review-<PR>concurrency group. Recovering meant re-running thepull_requestrun once nothing else was in flight.Suggested fix
Detect this specific signature — action skipped for workflow validation, zero execution output — and have
run-review-guardskip rather than fail, the way it already skips for quota exhaustion. A dispatched review that was never allowed to start is not a failed review, and reporting it as one trains readers to ignore a redrequire-review, which is the check's whole value.Worth pairing with a log line naming the cause, since the current error message ("produced no execution output") describes the symptom and gives no hint that a workflow-file change is why.
Not urgent
No correctness or security impact; the
pull_request-triggered review still works, and the failure is loud rather than silent. The cost is a red required check that has to be diagnosed by hand each time, plus the cancellation collateral above.