From 165711d75b1ffba39f85238b0015d1b935b5c95a Mon Sep 17 00:00:00 2001 From: Joseph Mearman Date: Thu, 17 Sep 2026 15:21:57 +0100 Subject: [PATCH] fix(review): surface the head commit so a resumed session can't mistake a re-review for a repeat A resumed session (resume_sessions: true, the default) carries every prior commit's conversation forward as one growing transcript, but nothing in the composed prompt states the current head commit explicitly. On a long-lived pull request the model has no mechanical way to check its own resumed memory against reality, and can conclude a new commit is the same one it already reviewed. Add the head commit SHA as its own fact line in the "This run" section for review mode, resolved from the same pull-request event context the gate step already uses, and always present regardless of resume_sessions. Also instruct the model, in the re-review section of the review prompt, to check that fact against what it actually remembers reviewing before treating a run as a repeat. --- action.yml | 4 ++++ prompts/review/base.md | 2 ++ 2 files changed, 6 insertions(+) diff --git a/action.yml b/action.yml index da03ea0..730ecb8 100644 --- a/action.yml +++ b/action.yml @@ -941,6 +941,7 @@ runs: EVENT_ACTION: ${{ github.event.action }} ENTITY_NUMBER: ${{ inputs.pr_number || inputs.issue_number || github.event.pull_request.number || github.event.issue.number }} BASE_REF: ${{ github.event.pull_request.base.ref }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} SEVERITY_RATINGS: ${{ inputs.severity_ratings }} ALLOWED_REVIEW_STATES: ${{ inputs.allowed_review_states }} INCLUDE_SUGGESTIONS: ${{ inputs.include_suggestions }} @@ -1053,6 +1054,9 @@ runs: printf -- '- Pull request base branch: `%s`\n' "$BASE_REF" fi if [ "$MODE" = "review" ]; then + if [ -n "${HEAD_SHA:-}" ]; then + printf -- '- Head commit: `%s`\n' "$HEAD_SHA" + fi if [ -n "${STACK_NAMES:-}" ]; then printf -- '- Detected stack: `%s`\n' "$STACK_NAMES" else diff --git a/prompts/review/base.md b/prompts/review/base.md index a6dbc0b..4737935 100644 --- a/prompts/review/base.md +++ b/prompts/review/base.md @@ -120,6 +120,8 @@ Rules for a suggestion, when on: The "Resolve stale threads" line in the "This run" section says whether to clean up your own prior moderation on a re-review -- dismissing superseded reviews and resolving or updating your own prior review threads, all described below. When it is **on** (the default), do this _before_ submitting the new review, and only on a re-review -- a pull request that already has a review from you (github-actions\[bot\]) on an earlier commit. Separately, the "Verify prior findings" line, described in its own paragraph further down, governs whether you must re-check a past technical claim before relying on it again when deciding to leave a thread open on a re-review. +**Before treating this as a re-review of a commit you have already seen, check the "Head commit" line in the "This run" section above against the commit your own memory of this conversation actually reflects.** If your session was resumed from an earlier run, its transcript can span many prior commits on this same pull request, and a resumed session feeling continuous is not evidence that the head commit has not moved since your last turn in it -- confirm the two actually match (for instance, against the `commit_id` of your most recent review via `gh api repos/{owner}/{repo}/pulls/{number}/reviews`) before reusing any earlier conclusion. If they do not match, this is a genuinely new commit: give it a full, real review, and never carry forward a finding, or a "nothing has changed" judgement, from a different commit than the one named in "Head commit" above. + **Dismiss your own prior reviews, whatever state they were submitted in, after clearing each one's body first.** A stale review from a prior commit no longer reflects the code at the current revision, and GitHub does not treat a new review from the same reviewer as superseding the old one: a stale `CHANGES_REQUESTED` keeps blocking the merge gate after you submit a fresh review, and a stale `APPROVED` keeps sitting in the reviewer list looking like a current green light for code that has since changed underneath it -- exactly as misleading in the other direction. Dismissing a review only changes its state, though: GitHub does not clear or hide a review's body when it is dismissed, so the full prose write-up of a dismissed review keeps displaying on the pull request timeline forever, looking exactly as current as the day it was posted, unless you clear it explicitly. Before submitting your new review, find your prior reviews via `gh api repos/{owner}/{repo}/pulls/{number}/reviews`, filter to those from your own login with `state == "CHANGES_REQUESTED"`, `state == "APPROVED"`, or `state == "DISMISSED"` -- include the already-dismissed ones too, since a review dismissed by an earlier run of this bot, before this body-clearing step existed, is still sitting on the timeline with its original write-up intact and needs the same cleanup now, not just reviews you are dismissing for the first time. For each, clear its body first with `gh api --method PUT repos/{owner}/{repo}/pulls/{number}/reviews/{review_id} -f body=""`, unconditionally, even one already dismissed; then, only if it is not already `DISMISSED`, dismiss it with `gh api --method PUT repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}/dismissals -f message="Superseded by re-review on the latest commit." -f event="DISMISS"` -- a review already in that state has nothing left for the dismissal call to do. Do this regardless of what your new review's own verdict turns out to be -- even a fresh `APPROVED` supersedes a stale one, since the stale one was never a verdict on this revision. `COMMENT` reviews need no dismissal: they neither block nor approve, so there is nothing live to clear. Do not clear the body of, or dismiss, reviews from other reviewers -- only your own. **Resolve addressed threads.** Fetch your prior review threads with `gh api graphql`, asking for each thread's node ID, path, line, whether it is already resolved, and the author login of its first comment. Filter to threads you opened that are still **unresolved**. For each, judge against the current revision whether the finding is now addressed -- the commented line changed and the issue is gone. If it is addressed, resolve the thread with `mcp__github__resolve_review_thread` (passing that thread's node ID). If the finding still applies, leave the thread open; your new review can re-reference it -- unless only the comment's own anchor has drifted while the finding itself still holds, which the next paragraph covers instead. Do not resolve a thread just because it is old -- only because the change fixed it.