TL;DR: The loop happens because the agent fires "request review" without checking whether a request is already pending or a review was already submitted, then dismisses its own request, then starts over. Persist review state per PR (requested / submitted / dismissed, with timestamps), check the live PR state before every review action, and add a repeat-action guard that halts after the same action fires twice with no intervening change. That breaks the cycle and leaves exactly one review request per PR.

```text
agent loop: requested review, dismissed it, requested review again
```

1. Read the PR's live review state first. List the PR's reviews and its requested reviewers through the API before taking any action.
   Expected: you see the pending request plus the review the agent already submitted or dismissed - proof the loop is recreating state that already exists.
2. Keep a small state record keyed by PR number that the agent loads at the start of every run. Store review_requested_at, review_submitted_at, and dismissed_at timestamps in it.
   Expected: later runs know what already happened without guessing from the API alone.
3. Gate the request-review action. Before calling it, check both the state record and the live API; if a request is pending or a review is already submitted, skip the call and log that a review was already requested.
   Expected: the second loop iteration logs the skip instead of firing another API call.
4. Separate dismissal from requesting. Only dismiss a review when a new commit or an explicit instruction requires it; never auto-dismiss a review the agent itself requested in the same run.
   Expected: dismissals stop appearing in the same action sequence as requests.
5. Add a repeat-action guard. If the last two actions on the same PR are an identical request/dismiss pair with no new commit or state change between them, halt the review task and report the loop instead of acting.
   Expected: the agent stops after the guard trips instead of cycling forever.
6. Re-run the review task on a test PR and inspect the action log.
   Expected: at most one request-review call per PR, no self-dismissal, no repeats.

## Use this when
- Request-review, dismiss-review, request-review appears for the same PR in the action log
- The agent's actions repeat with no new commits between them
- Review requests pile up on a PR the agent already reviewed
- The agent dismisses reviews it created itself

## Not for this skill when
- A human reviewer manually dismissed the review (check the dismissing actor first)
- The PR genuinely needs re-review after new commits were pushed (that is new state, not a loop)
- Review calls are failing with 403 or 404 (that is a permissions or existence problem)
- The agent is stuck waiting on API rate limits rather than repeating actions

## Variant phrasings
- "review bot keeps requesting review after dismissing it"
- "agent stuck requesting and dismissing PR reviews in a loop"
- "duplicate review requests on the same pull request"
- "agent dismisses its own review then requests a new one"

## Why it happens
Most review agents treat "make sure a review is requested" as an unconditional step with no memory of what already happened. Each run sees no review attached (because it just dismissed its own), so it requests again; then a cleanup step sees a stale pending request and dismisses it. Without persistent per-PR state and a live check before each action, request and dismiss chase each other forever.

## Edge cases
- The state record goes stale if a human merges or closes the PR. Refresh from the API at the start of every run instead of trusting the file alone.
- Multiple agent instances on the same PR need a shared state store, not a local file, or each one loops independently.
- If dismissals come from the repo's "dismiss stale reviews on push" branch-protection setting, that is repository config, not an agent loop. Check repo settings before changing agent behavior.
- Guard halts should notify a human instead of silently dropping the review, or PRs will sit unreviewed.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_S000wVg5KwH9B38tevBHkA
