Flapping and Convergence
What happens when agents get stuck in loops, oscillate between competing approaches, or fail to converge on a stable outcome? Detection, circuit-breaking, and remediation for non-converging agent behavior.
Related:
- agent-architecture.md — agent roles and coordination
- code-review.md — review agent behavior
- autonomy-spectrum.md — autonomy and escalation
- adaptive-agent-selection.md — choosing agent configurations
- cross-run-memory.md — learning from prior failures
The problem
Agents can get stuck in loops where they repeatedly attempt and fail the same task, or oscillate between competing approaches without settling on a solution. This "flapping" wastes LLM spend, blocks real work, and can pollute PR histories with dozens of failed attempts.
Flapping is distinct from normal retry behavior. A single retry after a transient failure is healthy. Flapping is when the system does not converge: each attempt either reproduces the same failure or introduces a new one that reverses the previous fix.
Types of flapping
Fix-break oscillation. An agent fixes file X, which breaks file Y. It then fixes file Y, which breaks file X again. The agent cycles between two states, never reaching one where both files work. This is common when changes have coupled dependencies that the agent does not model holistically.
Review ping-pong. An agent submits a PR. The review agent requests changes. The code agent addresses the feedback, but the fix introduces a new issue. The review agent catches the new issue. The code agent fixes it but reintroduces the original problem. The PR accumulates comments without progress.
Approach churn. An agent tries approach A, it fails. It tries approach B, it also fails. It goes back to approach A (having forgotten it already tried it, or hoping conditions changed). This is especially common in stateless agents with no cross-run memory.
Flaky-test loops. An agent adds a test, the test passes locally but fails in CI (flaky). The agent modifies the test, CI passes, but a different test becomes flaky. The agent chases intermittent failures indefinitely.
Why this matters at scale
A single flapping agent on one repo is annoying. Twenty flapping agents across an organization's repositories are a resource drain. At production scale (dozens of repos, multiple agent roles per repo), flapping becomes an operational problem:
- Cost. Each iteration consumes LLM tokens. Eight review cycles at $2-5 per cycle on a single PR adds up across hundreds of PRs.
- Noise. PRs with 40+ bot comments are impossible for humans to review. The signal is buried in the noise of failed attempts.
- Blocking. While an agent flaps on one issue, other issues in the same repo may be queued behind it, depending on concurrency limits.
- Credibility. Human maintainers who see agents repeatedly failing lose confidence in the system, even for tasks the agents handle well.
Detection
Cycle detection via state hashing
The harness tracks a fingerprint of each iteration's key state: the approach taken, the files modified, the test results, and the review outcome. If the same fingerprint appears twice within a configurable window (default: 3 iterations), the agent is cycling.
The fingerprint does not need to be an exact match. Fuzzy matching (e.g., "the same files were modified in similar ways") catches near-cycles where the agent makes trivially different changes that produce the same failure.
Diff-distance damping
Each iteration's diff is compared to the previous iteration's diff. If the diffs are inverses (lines added in iteration N are removed in iteration N+1, and vice versa), the agent is oscillating. A damping metric measures how much of each diff reverses the previous diff: a value above a threshold (e.g., 70% reversal) triggers a flapping alert.
Cost and turn accounting
The functional test framework (#1682) already enforces max_turns and max_cost_usd per run. Extending these thresholds across retries catches slow-burn flapping: an agent that uses 5 turns per attempt but makes 8 attempts has consumed 40 turns total, which may exceed the cross-run budget even if each individual run was within bounds.
Review comment velocity
A simpler heuristic: if a PR accumulates more than N review comments (e.g., 20) without being merged or closed, something is wrong. This does not distinguish flapping from genuinely complex reviews, but it flags PRs that need human attention.
Response strategies
Circuit breaker with escalation
After detecting flapping (by any of the methods above), the harness stops the agent and escalates to a human. The escalation message includes: what was attempted, how many iterations, what the recurring failure pattern is, and a recommendation for what a human should look at.
This is the safest response. It prevents further waste and gives humans the context they need to intervene efficiently. The downside: it puts work back on humans, which is what automation was supposed to reduce.
Strategy rotation
Instead of escalating immediately, the harness tries a different agent configuration. If the code agent with default instructions is flapping, try a different model, different temperature, or a specialized skill. If the review agent and code agent are ping-ponging, try a different review configuration.
This connects to adaptive-agent-selection.md: the selection mechanism could treat flapping as a negative fitness signal for the current configuration and promote an alternative.
The risk: strategy rotation without a flapping budget can itself become a form of flapping at the meta-level, cycling through configurations without converging.
Cooldown with context injection
Pause the agent for a cooldown period, then resume with additional context: "you have attempted this task N times. Previous attempts failed because [summary]. Do not repeat approach X." This requires some form of cross-run memory (see cross-run-memory.md), which has its own trust and safety implications.
Abandon and report
After exhausting retry and strategy budgets, close the PR or issue with a structured report: what was tried, why it failed, and what a human would need to resolve it. This is the most honest response: some tasks are beyond the agent's current capability, and acknowledging that is better than wasting resources.
Thresholds and configuration
Flapping detection needs configurable thresholds because different repos and task types have different tolerance for iteration:
- A documentation repo might tolerate only 2 review cycles before escalating.
- A complex backend service might allow 5 cycles before escalating, because multi-file changes legitimately require more iteration.
- Security-sensitive paths should have lower thresholds than non-sensitive paths.
Default thresholds should be conservative (escalate early) and configurable per repo and per agent role.
Relationship to other problem areas
- Adaptive Agent Selection — Flapping is a negative fitness signal. Configurations that produce flapping should be penalized in the selection mechanism. Strategy rotation is a form of adaptive selection triggered by failure.
- Cross-Run Memory — Context injection during cooldown requires memory. Flapping detection across runs requires tracking prior attempts. Both create the trust and poisoning concerns that cross-run memory addresses.
- Operational Observability — Flapping agents are a key operational concern. Dashboards should surface flapping rate per repo, per agent role, and per task type.
- Code Review — Review ping-pong is one specific form of flapping. The code-review doc describes the review process but does not address what happens when the process does not converge.
- Trustworthiness Evidence — Flapping rate is a negative trustworthiness signal. An agent that flaps frequently on a repo is less trustworthy than one that converges reliably.
Open questions
- What is the right default flapping budget (max iterations before circuit-breaking)? Should it be count-based, cost-based, or time-based?
- Should strategy rotation happen before or after human escalation? Or should it be a configurable policy?
- How should flapping be reported to humans? A structured report is ideal, but generating a useful summary of N failed attempts is itself a non-trivial task.
- Can flapping be predicted from task characteristics (e.g., cross-module changes, missing tests, coupled dependencies) before the agent starts?
- Should the harness maintain a "known-flapping" list of issues that should not be retried without human intervention?
