Problem
When an agent workflow posts a REQUEST_CHANGES review via submit-pull-request-review, the blocking review persists even after the author fixes all findings and triggers a re-review. The new review run cannot dismiss the stale blocking review because:
- gh-aw enforces
pull-requests: read — pull-requests: write is rejected by the compiler (correctly, for security)
- There is no
dismiss-pull-request-review safe output type
- The
hide-older-comments: true option on add-comment has no equivalent for reviews
Net result: A stale CHANGES_REQUESTED review from github-actions[bot] blocks the PR indefinitely until a human manually dismisses it.
Real-World Impact
- PureWeen/PolyPilot#619: A 3-model adversarial code review posted
REQUEST_CHANGES on commit 1. The author fixed all 4 findings in commits 2-6. Re-running /review posted a new review but the old blocking review persisted, preventing merge.
- dotnet/maui#35027: The MAUI repo adopted
allowed-events: [COMMENT] as a workaround after discovering the same issue.
- gh-aw#25869: The
design-decision-gate workflow independently removed submit-pull-request-review entirely to avoid stale blocking reviews — same workaround pattern.
- tailspin-toys-workshop: The gh-aw workshop teaches
allowed-events: [COMMENT, REQUEST_CHANGES] as the recommended pattern, which would hit this problem if students use /review re-runs on their workflows.
Current Workaround
Use allowed-events: [COMMENT] to prevent the agent from posting blocking reviews. The review body still communicates severity through findings, but this loses:
- GitHub-native "Changes requested" badge and merge-blocking semantics
- PR list discoverability (no blocking indicator at a glance)
- Branch protection integration (bot reviews cannot gate merge)
Proposed Solution
Add a supersede-older-reviews: true option to submit-pull-request-review, analogous to hide-older-comments: true on add-comment:
safe-outputs:
submit-pull-request-review:
max: 1
allowed-events: [COMMENT, REQUEST_CHANGES]
supersede-older-reviews: true # dismiss prior bot reviews from same workflow
Behavior
When posting a new review, auto-dismiss previous REQUEST_CHANGES reviews from the same workflow (identified by GITHUB_WORKFLOW / workflow-id marker) on the same PR. The dismissal message would be "Superseded by updated review from same workflow."
Why not a standalone dismiss-pull-request-review safe output?
A standalone dismiss primitive has a wider attack surface — an agent could be prompt-injected into dismissing legitimate human reviews. supersede-older-reviews is structurally safer because:
- Scoped to the same workflow's own prior reviews (never human reviews)
- Atomic with posting a new review (cannot dismiss without replacing)
- Matches the existing
hide-older-comments pattern exactly
- No new permissions exposure — the
pull-requests: write needed for dismissal stays inside platform infrastructure
Security Analysis (4-model adversarial consensus)
This proposal was reviewed by 4 independent AI models with adversarial consensus. All 4 unanimously agreed the problem is real. However, on the proposed solution, 2/3 disagreed — raising important concerns that should inform the design:
| Threat |
Risk |
| Prompt injection → dismiss human reviews |
Impossible — scoped to same-workflow bot reviews only |
| Prompt injection → dismiss to unblock merge |
Cannot dismiss without simultaneously posting a replacement review |
| Branch protection bypass |
Marginal — the new review replaces the old one, so net review state is fresh, not absent |
| Scope creep |
Cannot target other bots/humans — scoped by workflow identity |
⚠️ Counter-Arguments (from adversarial review)
We ran a 3-model adversarial review of this issue itself. Two of three reviewers disagreed with the proposed supersede-older-reviews design, raising valid concerns:
Atomicity is false
The hide-older-comments analogy breaks down because dismiss + post is two separate GitHub API calls, not a transaction. If dismiss succeeds but the new review POST fails (network error, rate limit, model timeout), the PR is left unblocked with no review — a security regression.
Auto-merge race condition
If a repo has auto-merge enabled: dismiss fires → PR satisfies all merge conditions → GitHub auto-merges → new review arrives after merge. The PR merges without the replacement review ever being evaluated.
Stale REQUEST_CHANGES as a security ratchet
A stale blocking review requires human judgment to dismiss. This is arguably a security feature, not a bug — it prevents a prompt-injected "clean" re-review from automatically unblocking a PR that had legitimate findings. The human dismissal step is a trust boundary.
"Same workflow" identity is underspecified
How does the platform determine which previous reviews belong to "this workflow"? All gh-aw workflows share github-actions[bot] as the actor. Workflow file path, run ID lineage, or a platform metadata store? Each has different security properties.
Alternative Approaches
Given these concerns, the gh-aw team may prefer one of these alternatives:
Option A: Codify [COMMENT] as the recommended pattern (lowest risk)
Update the docs to explicitly recommend allowed-events: [COMMENT] for review workflows. This is already what every team in this issue converged on. Bot reviews inform; humans control merge-blocking.
Option B: Explicit dismiss-pull-request-review safe output (higher visibility)
A separate safe output (not bundled as a side effect of posting) with:
scope: same-workflow — only reviews posted by same workflow identity
require-replacement: true — must be paired with a new review in the same run
max: 1 — rate limited
This makes the permission grant visible in the workflow definition and auditable.
Option C: create-check-run for bot blocking
Status checks (required_status_checks) are purpose-built for bot blocking signals — independent of the human review flow, easy to re-run and replace, no dismiss semantics needed.
Precedent
add-comment already supports hide-older-comments: true with similar lifecycle semantics. However, as noted in the counter-arguments, hiding a comment is cosmetic (content still accessible), while dismissing a REQUEST_CHANGES review is a branch protection state change — categorically different operations.
The current submit-pull-request-review docs (reference) confirm no lifecycle management option exists today. The only options are: max, target, target-repo, allowed-repos, allowed-events, footer.
Problem
When an agent workflow posts a
REQUEST_CHANGESreview viasubmit-pull-request-review, the blocking review persists even after the author fixes all findings and triggers a re-review. The new review run cannot dismiss the stale blocking review because:pull-requests: read—pull-requests: writeis rejected by the compiler (correctly, for security)dismiss-pull-request-reviewsafe output typehide-older-comments: trueoption onadd-commenthas no equivalent for reviewsNet result: A stale
CHANGES_REQUESTEDreview fromgithub-actions[bot]blocks the PR indefinitely until a human manually dismisses it.Real-World Impact
REQUEST_CHANGESon commit 1. The author fixed all 4 findings in commits 2-6. Re-running/reviewposted a new review but the old blocking review persisted, preventing merge.allowed-events: [COMMENT]as a workaround after discovering the same issue.design-decision-gateworkflow independently removedsubmit-pull-request-reviewentirely to avoid stale blocking reviews — same workaround pattern.allowed-events: [COMMENT, REQUEST_CHANGES]as the recommended pattern, which would hit this problem if students use/reviewre-runs on their workflows.Current Workaround
Use
allowed-events: [COMMENT]to prevent the agent from posting blocking reviews. The review body still communicates severity through findings, but this loses:Proposed Solution
Add a
supersede-older-reviews: trueoption tosubmit-pull-request-review, analogous tohide-older-comments: trueonadd-comment:Behavior
When posting a new review, auto-dismiss previous
REQUEST_CHANGESreviews from the same workflow (identified byGITHUB_WORKFLOW/ workflow-id marker) on the same PR. The dismissal message would be "Superseded by updated review from same workflow."Why not a standalone
dismiss-pull-request-reviewsafe output?A standalone dismiss primitive has a wider attack surface — an agent could be prompt-injected into dismissing legitimate human reviews.
supersede-older-reviewsis structurally safer because:hide-older-commentspattern exactlypull-requests: writeneeded for dismissal stays inside platform infrastructureSecurity Analysis (4-model adversarial consensus)
This proposal was reviewed by 4 independent AI models with adversarial consensus. All 4 unanimously agreed the problem is real. However, on the proposed solution, 2/3 disagreed — raising important concerns that should inform the design:
We ran a 3-model adversarial review of this issue itself. Two of three reviewers disagreed with the proposed
supersede-older-reviewsdesign, raising valid concerns:Atomicity is false
The
hide-older-commentsanalogy breaks down because dismiss + post is two separate GitHub API calls, not a transaction. If dismiss succeeds but the new review POST fails (network error, rate limit, model timeout), the PR is left unblocked with no review — a security regression.Auto-merge race condition
If a repo has auto-merge enabled: dismiss fires → PR satisfies all merge conditions → GitHub auto-merges → new review arrives after merge. The PR merges without the replacement review ever being evaluated.
Stale REQUEST_CHANGES as a security ratchet
A stale blocking review requires human judgment to dismiss. This is arguably a security feature, not a bug — it prevents a prompt-injected "clean" re-review from automatically unblocking a PR that had legitimate findings. The human dismissal step is a trust boundary.
"Same workflow" identity is underspecified
How does the platform determine which previous reviews belong to "this workflow"? All gh-aw workflows share
github-actions[bot]as the actor. Workflow file path, run ID lineage, or a platform metadata store? Each has different security properties.Alternative Approaches
Given these concerns, the gh-aw team may prefer one of these alternatives:
Option A: Codify
[COMMENT]as the recommended pattern (lowest risk)Update the docs to explicitly recommend
allowed-events: [COMMENT]for review workflows. This is already what every team in this issue converged on. Bot reviews inform; humans control merge-blocking.Option B: Explicit
dismiss-pull-request-reviewsafe output (higher visibility)A separate safe output (not bundled as a side effect of posting) with:
scope: same-workflow— only reviews posted by same workflow identityrequire-replacement: true— must be paired with a new review in the same runmax: 1— rate limitedThis makes the permission grant visible in the workflow definition and auditable.
Option C:
create-check-runfor bot blockingStatus checks (
required_status_checks) are purpose-built for bot blocking signals — independent of the human review flow, easy to re-run and replace, no dismiss semantics needed.Precedent
add-commentalready supportshide-older-comments: truewith similar lifecycle semantics. However, as noted in the counter-arguments, hiding a comment is cosmetic (content still accessible), while dismissing a REQUEST_CHANGES review is a branch protection state change — categorically different operations.The current
submit-pull-request-reviewdocs (reference) confirm no lifecycle management option exists today. The only options are:max,target,target-repo,allowed-repos,allowed-events,footer.