review:follow-up · git:20261018.ea39d1d · 2026-10-18 · sha256 7dd0edbfa1ef2ae2
review:follow-up git:20261018.ea39d1dA
Immutable. This exact content never changes and is served at /api/v1/blob/7dd0edbfa1ef2ae2.
---
name: review:follow-up
description: >
Follow up as the reviewer on a PR/MR you reviewed: did the author's fixes actually grasp
each concern you raised, or just go through the motions? Finds silently resolved or
mechanically-fixed threads and returns a graded re-review call. Use when you left review
comments and want to verify the author acted on them before re-approving. Triggers: "did they
fix my review comments", "re-review this PR", "check whether the author addressed my feedback".
argument-hint: "[pr-url]"
disable-model-invocation: true
allowed-tools:
- Bash(gh:*)
- Bash(glab:*)
- Bash(git:*)
- Agent
---
# Review Follow-Up
Follow up on my review of: $ARGUMENTS
You are the reviewer. The question is not "did the author reply?" but "did the fix actually grasp each concern, or go through the motions?" Status is a signal. The code is the verdict. Report any mismatch between the two (resolved but not fixed, unresolved but fixed) as a finding.
All diff and file reading happens in Explore sub-agents. Your main session holds only the structured verdicts they return, never raw diffs, keeping my development context free.
## Context
- Remote URL: !`git remote get-url origin 2>/dev/null || echo "unavailable"`
- Branch: !`git branch --show-current 2>/dev/null || echo "unavailable"`
## Workflow
### Resolve Target
If `$ARGUMENTS` carries a URL or identifier, use it. If it's empty, detect the current branch's open PR/MR. Pick the platform from `git remote get-url origin`, then:
- GitHub: `gh pr view --json url,state --jq '.url'`
- GitLab: `glab mr view --output json | jq -r '.web_url'`
Both resolve the current branch with no positional argument. Ask me for a URL only if detection comes up empty. A closed or merged PR still resolves, so surface the `state` for me to confirm before proceeding.
For GitLab, load the `gitlab:api` and `gitlab:merge-request` skills for API patterns and MR tooling.
### Sync to the Latest Pushed State
Your assessment must reflect what the author actually pushed. The worktree-behind-origin trap: judging a local worktree that is N commits behind origin makes clean fixes look unaddressed. Never assess local state without syncing.
- Prefer the remote-of-record diff. `glab` and `gh` API diffs always reflect the server, so favor them over the local worktree.
- If a sub-agent must read the local worktree, it has to `git fetch` first and compare against `origin/<branch>`, never the local checkout.
- **Behind is not divergent.** A local branch that differs from the PR head is not automatically your own in-progress rework. `git merge-base --is-ancestor HEAD origin/<branch>` succeeding means you are simply behind origin. Only if it fails has the local branch actually left the PR's history.
Establish the **review baseline**: the commit/version at which you last reviewed, plus current head. The fix assessment diffs that range, not the whole MR.
- GitLab: the `gitlab:merge-request` skill exposes MR versions and `diff_refs` to bound the range from your last-reviewed version to head.
- GitHub: use your review's commit SHA to head.
### Fetch Threads
Gather all resolvable discussion threads that I started (both resolved and unresolved). Retain each thread's **original comment body and location**. The sub-agents need the concern's intent, not its status.
#### GitHub
Use the `github:pr-comments` skill's script with `--role reviewer --include-resolved` to get every thread you started, resolved and unresolved, each with its full comment chain so silent resolves are visible. Do not pass `--since`. Follow-up needs the whole history.
If a query ever needs hand-authoring (fetching `reviewThreads` is the usual case), write it to a `.graphql` file with the Write tool and pass `gh api graphql -F query=@query.graphql`. Capital `-F` reads the query from a file, which keeps a long multi-line query out of the command line.
#### GitLab
Use the `gitlab:merge-request` skill's discussions script, which that skill documents. Resolve your username first, then fetch the resolvable threads you started, resolved and unresolved, with every note: `discussions.ts list <iid> --resolvable --author <username> --format raw`. You need each thread's original body, its location, and the author's later replies, which the default first-note summary drops.
### Classify Threads
Bucket each thread by resolution status and whether the author replied, treating the bucket as a **signal, not a verdict**. A system-generated note (a version or diff note, not a human comment) is **not** a substantive reply. Don't count it as the author engaging with the concern. The fetch step's skill covers how these look on each platform.
### Assess Fixes
The core step. Dispatch read-only Explore sub-agents (`Agent` tool) to read the post-review diff and judge each fix. **Group threads by the file they sit on and dispatch one Explore agent per file.** When a single file carries many threads, fall back to per-thread agents. Cap parallelism at roughly 6-8 concurrent.
Give each agent:
- the file path
- every thread on that file: original comment body, location, and the underlying intent
- the review-baseline→head diff range from the sync step
Each agent reads that file's post-review diff **once** and returns a compact structured verdict per thread. **No raw diffs come back**, only these fields:
- `location`: `file:line` or thread id
- `concern`: the original intent, one line
- `change`: what the author actually did, code-grounded, one line (or "no change found")
- `verdict`: `Addressed` | `Partial` | `Not addressed` | `Dismissed` | `Can't tell`
- `quality`: `Solid` | `Mechanical` (satisfies the words, misses the intent) | `Went further` | `Adopted verbatim` | `Workaround/band-aid` | `Introduced new issue` | `n/a` (use when nothing changed; quality only applies to a fix that exists)
- `status_mismatch`: e.g. "resolved but not actually fixed", "unresolved but fixed", or none
- `confidence`: `high` | `med` | `low`
- `focus`: boolean, does this warrant my eyes
Spell out these assessment lenses in each agent's prompt:
- Does the fix address the underlying concern, or only the literal surface words?
- Is it partial, fixing one call site but not the others, or handling the happy path only?
- Was it dismissed? If so, is the dismissal reasonable?
- Did the author go further than asked, or adopt my wording verbatim (a sign they fed my comment back into a model without engaging)?
- Did the fix introduce a new issue near the change?
### Quick Pass for New Issues
Have the same per-file agents flag problems the fixes **introduced** that aren't tied to any thread. Surface these separately from the thread verdicts.
### Verify Author Claims
If the author claims they tested, validated, or ran something, check for evidence: relevant commits, test changes, MR-body checkboxes that are checked. Flag unsubstantiated claims rather than taking them at face value.
### Present: Attention-Ranked Report
Lead with what needs my eyes. Don't emit a uniform full-detail row per thread.
#### Needs Your Attention
Flagged thread verdicts (`focus = true`), new issues, and unverified claims. Each one concise and code-grounded, with its confidence. Include any status-vs-reality mismatch.
#### Cleanly Addressed
Collapse solid fixes to a count plus one-liners. Don't expand them.
#### Recommendation
A graded call:
- **Approve**: everything addressed cleanly
- **Approve with comments**: addressed, with minor nits you can fix in a follow-up PR
- **Request changes**: partial, mechanical, or unaddressed concerns remain
### Execute Actions
After I decide on next steps, use platform-appropriate commands:
#### GitHub
- Approve: `gh pr review --approve`
- Comment: `gh pr comment`, with `--attach ./shot.png` for a screenshot the comment references (load `github:attach`)
- Resolve thread: `gh api graphql` with `resolveReviewThread` mutation
##### Draft a Pending Review
Often the end goal is a set of draft inline comments I submit myself from the GitHub UI. Create a pending review: write a `payload.json` with `commit_id`, a top-level `body`, and a `comments[]` array, then `gh api --method POST repos/{owner}/{repo}/pulls/{n}/reviews --input payload.json`. Each comment object carries `path`, `line`, `side` (`RIGHT`), and `body`. Omit the `event` key entirely. Its absence is what keeps the review pending for me to finish and submit from the GitHub UI.
- **Anchor lines to the cumulative diff.** Every `line` must exist in `gh pr diff <n>` (cumulative), not `gh pr diff --patch` (per-commit patches give wrong offsets). GitHub rejects any line outside the diff. Listing a pending review's comments reports `line` as null until the review is submitted, so don't read that as a failed anchor.
- **No draft replies onto existing threads.** A pending review can't thread a reply onto an existing review thread through the API. When a resolved thread was only partially addressed, re-raise the remaining point as a new inline comment at the same `file:line` inside the pending review.
#### GitLab
Approve, resolve or unresolve threads, and comment via the `gitlab:merge-request` skill.
## Guardrails
- **Check with me** before submitting any review or comments.
- **Don't approve automatically**: present the evidence, let me decide.