---
name: review-loop
description: Iterates code review until convergence — addressing every comment, re-requesting review, and stopping only when the diff is clean and approved. Use after opening a pull request, when review feedback arrives in batches, or when closing out comments one-by-one loses track of what remains.
category: loop-engineering
keywords: code-review, pull-request, iteration, feedback, convergence
---

# Review Loop

## When to apply

Use whenever a change is under review: after opening a pull request, when review comments arrive, or when fixes spawn further comments. The loop's exit condition is an **approved, comment-free diff** — not "I replied to everything".

## Workflow

1. **Inventory** — List every review comment and CI check. Each gets an entry: `comment → owner (you) → state (open/done/disputed)`.
2. **Triage each comment** into:
   - **Fix** — address exactly as asked
   - **Clarify** — comment was based on a misreading; answer precisely, change nothing
   - **Dispute** — you believe the reviewer is wrong; state your reasoning and evidence, offer to defer
3. **Apply fixes in the review's priority order** — blocking comments before nits. Keep each fix minimal (see minimal-fix).
4. **Re-run the verification chain** — typecheck, tests, build. A comment addressed by code that breaks CI was not addressed.
5. **Re-request review** with a summary: what changed per comment, what's disputed and why.
6. **Check convergence**:
   - New comments on previously-commented lines → keep looping
   - Only style nits remain → apply or dispute once, then loop
   - Zero open comments + green CI + approval → **done**

## Worked example

```
PR #42: "Add user profile page"

Round 1 review — 3 comments:
| # | Comment                              | State    | Action                          |
|---|--------------------------------------|----------|---------------------------------|
| 1 | "Loading state missing"              | open     | Fix: add Suspense fallback      |
| 2 | "Why not use useQuery here?"         | open     | Clarify: useQuery needs a cache  |
|   |                                      |          | we don't have yet; noted in TODO |
| 3 | "Rename `data` to `profile`"         | open     | Fix: renamed                    |

Apply fixes → run tests → re-request review with summary:
  "1: fixed (added Suspense fallback). 2: clarified (no query cache yet,
  filed #43). 3: fixed (renamed)."

Round 2 review — 1 comment:
| # | Comment                              | State    | Action                          |
|---|--------------------------------------|----------|---------------------------------|
| 4 | "Fallback should show skeleton"      | open     | Fix: replaced spinner w/ skeleton |

Apply → test → re-request. Round 3: LGTM, CI green. **Done.**
```

## Stop conditions

- Approver says LGTM and no blocking checks remain → exit success
- A dispute cannot be resolved after two exchanges → escalate to a human decision, don't relitigate
- Loop count exceeds ~5 on the same comment → something is structurally wrong with the change; propose closing and splitting it

## Rules

- Never mark a comment "done" without the diff to show for it.
- Replies to every comment, even the ones you fix silently — reviewers shouldn't diff your diff to discover your response.
- Do not add unrelated improvements mid-review; they reset the review and the loop.

## Related skills

- [minimal-fix](/skills/minimal-fix) — The shape of each individual fix inside the loop.
- [loop-verifier](/skills/loop-verifier) — What the reviewer is (ideally) running on their side.
