Skip to content

Add circuit breaker to review-fix feedback loop #902

@fullsend-ai-retro

Description

@fullsend-ai-retro

What happened

On PR #799, the review agent and fix agent entered a feedback loop that ran 11+ full iterations across May 12-13. The sequence: review agent submits CHANGES_REQUESTED (flagging branch refs in workflow uses: directives) -> fix agent dispatched via dispatch-fix-bot on pull_request_review event -> fix agent pushes a commit -> pull_request_target/synchronize fires -> review agent dispatched again -> same finding flagged -> loop repeats. The fix agent could not resolve the branch-ref issue (it's intentional during development), so the loop never self-terminated.

The loop was broken twice by human intervention: ralphbean dismissed the review on May 12, and the fullsend-no-fix label was applied on May 13. Before that, the loop consumed ~36 review workflow runs (27 successful, 2 failed, 6 cancelled, 1 retro), generated 27 orphaned notification comments, and submitted 13 redundant CHANGES_REQUESTED reviews that all flagged the same issue.

Existing proposals #893 (reduce redundant dispatches) and #887 (cancel in-flight reviews) are complementary but do not address the core loop: a fix agent push is a legitimate synchronize event, so neither event filtering nor concurrency cancellation would prevent the next review from dispatching.

What could go better

The review-fix loop needs a circuit breaker. Without one, any review finding that the fix agent cannot resolve will cause an infinite loop, bounded only by human intervention or the fullsend-no-fix label. This is high-confidence based on clear evidence: 11+ identical cycles on a single PR.

The circuit breaker should operate at the dispatch layer (in fullsend.yaml or reusable-dispatch.yml) rather than inside the agents themselves, because the problem is in the dispatch logic, not the agent logic.

Possible approaches (not mutually exclusive):

  1. Iteration cap: Track how many review-fix cycles have occurred for a given PR (e.g., via a PR label like fix-attempt-N or a repo variable). After N iterations (e.g., 3), stop dispatching the fix agent and leave a comment asking for human review.
  2. Fix-result awareness: Have the fix agent report whether it actually changed anything. If the fix agent pushed no meaningful changes (or pushed changes but the same findings persist), do not re-dispatch.
  3. Duplicate-finding detection: Before dispatching the fix agent, check if the current review's critical findings are identical to the previous review's. If so, the fix agent already failed to resolve them -- escalate to human.

Approach 1 is simplest and most robust. Approach 2 requires fix agent output schema changes. Approach 3 requires cross-run state.

Proposed change

Add a review-fix iteration counter to the dispatch-fix-bot job in .github/workflows/fullsend.yaml (or equivalent in reusable-dispatch.yml for per-repo mode). The counter should:

  1. On each dispatch-fix-bot trigger, check how many previous fix dispatches have occurred for this PR (e.g., by counting commits from fullsend-ai-code[bot] on the PR branch, or by checking for a fix-attempt-N label).
  2. If the count exceeds a threshold (suggest 3), skip the fix dispatch and post a comment: "Review-fix loop detected after N attempts. The following findings could not be auto-resolved: [list]. Requesting human review."
  3. Optionally apply the fullsend-no-fix label automatically when the threshold is hit.

This should be implemented in the fullsend-ai/fullsend repo since it's in the reusable workflow layer that all installations share.

Validation criteria

On the next PR where the fix agent cannot resolve a review finding, the loop should terminate after at most 3 review-fix cycles (6 total workflow runs: 3 reviews + 3 fixes) instead of running indefinitely. The PR should receive a human-readable comment explaining which findings could not be auto-resolved. Validate on the next 5 PRs that trigger fix agent runs.


Generated by retro agent from #799

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions