Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f33f0cb
feat(pr): auto-dismiss stale bot CHANGES_REQUESTED on push (#617)
don-petry Jul 14, 2026
dd4ef92
chore: dev-lead update (review-changes) [skip ci-relay]
donpetry-bot Jul 14, 2026
f2cb072
chore: dev-lead update (review-changes) [skip ci-relay]
donpetry-bot Jul 14, 2026
9855437
chore: dev-lead update (review-changes) [skip ci-relay]
donpetry-bot Jul 14, 2026
73ce669
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
da1dcbd
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
3723b70
fix(reviews): address review comments [skip ci-relay]
donpetry-bot Jul 14, 2026
ed06fea
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
fe18ff3
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
13b9ee5
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
de2f79b
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
8fb6ae5
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
fb2c6e7
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
4a08ab7
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
15def01
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 14, 2026
e6d1a38
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 15, 2026
e0b2e1e
fix(reviews): address review comments [skip ci-relay]
donpetry-bot Jul 15, 2026
8df0ad4
Merge branch 'main' into feat/dismiss-stale-bot-reviews-617
don-petry Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/workflows/dismiss-stale-bot-reviews.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Dismiss stale bot reviews
Comment thread
don-petry marked this conversation as resolved.

# Agent-PR merge friction (#617, blocker 3): a bot's CHANGES_REQUESTED review is
# NOT cleared by GitHub's `dismiss_stale_reviews_on_push` (that only dismisses
# stale *approvals*), so it persists on a superseded commit and blocks
Comment thread
don-petry marked this conversation as resolved.
# `reviewDecision` even with 0 unresolved threads — until the bot re-APPROVEs or
# a human dismisses it by hand. This workflow dismisses a bot's CHANGES_REQUESTED
# review once a NEWER commit has been pushed (the review is on a non-head SHA).
# Safe: it only ever touches reviews left by the allow-listed bots, and only ones
# on a superseded commit — those bots re-review the new head automatically, so a
# still-valid problem simply comes back as a fresh CHANGES_REQUESTED on the new SHA.

on:
pull_request:
types: [synchronize]
Comment thread
don-petry marked this conversation as resolved.
pull_request_review:
types: [submitted]

concurrency:
group: dismiss-stale-bot-reviews-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
dismiss:
name: Dismiss
permissions:
pull-requests: write # Required to dismiss PR reviews via API
# Same-repo PRs only — fork PRs get a read-only token that cannot dismiss.
# Skip Dependabot events: Dependabot `pull_request` runs receive no repo
# secrets (same constraint documented in dev-lead-reusable.yml lines 74-79),
# so GH_TOKEN is empty and the first `gh api` call fails even though there
# is no stale bot review to dismiss.
if: >-
github.actor != 'dependabot[bot]' &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Dismiss stale bot CHANGES_REQUESTED reviews
env:
# Classic PAT required: the dismiss-review endpoint rejects fine-grained
# tokens on protected branches; fall back to fine-grained only if classic
# is unavailable. See docs/pr-review-agent/bot-setup.md §75-83.
GH_TOKEN: ${{ secrets.DON_PETRY_BOT_GH_PAT_CLASSIC || secrets.DON_PETRY_BOT_GH_PAT }}
REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
# Space-delimited allow-list of bot review authors to auto-dismiss.
BOTS: "coderabbitai coderabbitai[bot]"
run: |
set -euo pipefail
dismissed=0
# Fetch reviews explicitly so enumeration failures surface as errors
# rather than silently producing an empty list via process substitution.
if ! reviews=$(gh api --paginate "repos/$REPO/pulls/$PR/reviews" \
--jq '.[] | [(.id|tostring), .user.login, .state, (.commit_id // "")] | @tsv'); then
echo "::error::Failed to enumerate PR reviews for $REPO#$PR"
exit 1
fi
# Iterate all reviews; act only on allow-listed bot CHANGES_REQUESTED
# reviews that sit on a commit other than the current head (i.e. superseded
# by this push). The bots re-review the new head automatically, so a
# still-valid concern returns as a fresh review on the new SHA.
while IFS=$'\t' read -r id user state sha; do
[ -n "$id" ] || continue
case " $BOTS " in *" $user "*) ;; *) continue ;; esac
[ "$state" = "CHANGES_REQUESTED" ] || continue
if [ -z "$sha" ] || [ "$sha" = "$HEAD_SHA" ]; then continue; fi
echo "Dismissing stale CHANGES_REQUESTED review $id by $user (on ${sha:0:8}, head ${HEAD_SHA:0:8})"
msg="Auto-dismissed (#617): \`$user\` CHANGES_REQUESTED on a superseded commit. The bot re-reviews the new head automatically — a valid concern will return as a fresh review."
if ! err=$(gh api -X PUT "repos/$REPO/pulls/$PR/reviews/$id/dismissals" \
-f message="$msg" \
2>&1 >/dev/null); then
echo "::error::could not dismiss review $id by $user. API said: $err"
exit 1
fi
dismissed=$((dismissed + 1))
done <<< "$reviews"
echo "Dismissed $dismissed stale bot review(s)."
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@ This is the `.github-private` org infrastructure repo for `petry-projects`. It c
not be removed by template syncs. If the org template gains a self-host caller-stub canary equivalent,
remove this exception and defer to the template instead.

- **Exception:** `dismiss-stale-bot-reviews.yml` (#617, blocker 3) is a documented repo-specific
workflow with no corresponding org template in `standards/workflows/`. It fires on
`pull_request: synchronize` and auto-dismisses allow-listed bot `CHANGES_REQUESTED` reviews
that are attached to a superseded (non-head) commit — GitHub's built-in
`dismiss_stale_reviews_on_push` only clears stale *approvals*, so bot CHANGES_REQUESTED
reviews blocked merges after a re-review was already approved. The allow-list is a
space-delimited `BOTS` env var in the workflow (currently `coderabbitai`); only same-repo PRs
are processed (fork PRs receive a read-only token). It must not be removed by template syncs.
If the org template gains an equivalent stale-bot-review dismissal, remove this exception and
defer to the template instead.

### Template drift guard (`repo-template`)

`petry-projects/repo-template` is a **distribution artifact** of the canonical `standards/` in the public
Expand Down
Loading