Skip to content

Stuck Loops and Thrash

When an agent is not converging, more prompting usually makes it worse. The context fills with refuted hypotheses, partial diffs, and self-reinforcing confidence. This page covers three operational faces of the same disease: loops (repeating a failing approach), thrash (oscillating between approaches while destroying working code), and silent scope creep during fixes (the "while I'm here" expansion that turns a one-line bugfix into a rewrite). The shared cure is: stop, cut context, re-ground in artifacts, restart narrow.


1. Stuck in loops

Symptoms

  • Same failing test fixed "three different ways," still red.
  • Agent re-proposes a hypothesis you already disproved.
  • File churn with no monotonic progress (diff oscillates).
  • Apologies + identical strategy restated with higher confidence.
  • Token burn climbing; wall clock climbing; quality not.

Root cause

Context poisoning: the model's own wrong explanation becomes part of the prior. Local search without new evidence cannot escape. See Production Debugging and Context Hierarchy.

Early detection

  • Two consecutive attempts with the same root-cause story → loop.
  • "Let me try adjusting the timeout/retry again" without new data.
  • Human feels the urge to "just one more prompt" — that urge is the alarm.

Prevention

  • Reproduce → hypothesize → instrument → fix; forbid fix-before-repro (Maintenance Prompts).
  • Cap attempts: "after 2 failed fixes, stop and summarize evidence."
  • Keep durable facts in a file (incident.md), not only in chat.

Recovery prompt

text
STOP implementing. Summarize in a short file:
- observations with evidence (logs, failing test output)
- hypotheses already tried and why they failed
- what is still unknown

Do not propose code yet. Then wait.

After that, new session with only the summary file + spec + failing test. Do not paste the old transcript.

Review checklist

  • [ ] Session killed once loop recognized
  • [ ] Evidence file exists; chat not the source of truth
  • [ ] Fresh session started without old rationalizations
  • [ ] Next change is the smallest experiment, not a rewrite

2. Thrash

Symptoms

  • Working code broken by a speculative refactor mid-fix.
  • Alternating patterns: "use Redux" → "remove Redux" → "use Redux again."
  • Git history is a sine wave; git bisect would be embarrassed.
  • Multiple incomplete migrations in one branch.
  • Tests deleted/rewritten repeatedly to match whichever approach is current.

Root cause

No stable success criterion; agent optimizes for local coherence of the latest idea. Ambiguous "make it clean" or "fix CI" without forbidding structural change invites thrash. Related economics in Specs Over Prompts: spinning the wheel is cheaper than thinking until it isn't.

Early detection

  • Net lines high, behavior progress low.
  • Reverts inside the same branch of large chunks.
  • Approach changes without an ADR/spec update.

Prevention

  • One approach per branch; approach change requires human approval + spec note.
  • Separate branches: fix/bug-123 vs refactor/....
  • Characterization tests before structural change (Reviewing AI Tests).

Recovery prompt

text
Thrash detected. Run git diff against <last-known-good-sha>.
Restore behavior to that baseline for <paths>, keeping only
the minimal bugfix if it is clearly correct and tested.

Discard incomplete refactors. List discarded approaches in
notes so we do not retry them in this branch. Do not start a
new architecture.

Prefer git checkout <good> -- <path> style restoration over asking the agent to "carefully undo."

Review checklist

  • [ ] Branch has one approach, not three half-approaches
  • [ ] Last known good identified; thrash discarded
  • [ ] Tests are not rewritten to follow thrash
  • [ ] Spec/ADR updated if approach intentionally changed

3. Silent scope creep during fixes

Symptoms

  • Ticket: null-check on invoice PDF. Diff: new PDF engine, dependency bump, folder restructure.
  • "Fixed flaky test" by rewriting the feature under test.
  • CI fix PR edits application logic unrelated to the failure.
  • Reviewer asked for a one-line change; agent delivered a framework.

Root cause

Fix prompts are under-specified ("fix it"), so the agent expands to aesthetically pleasing systems. Latest-instruction overweight + desire to look thorough. Cousin of unrelated files and easiest-vs-required under time pressure.

Early detection

  • Diff stat vs ticket size mismatch.
  • New dependencies on a "bugfix" PR.
  • Deleted edge cases or tests as part of a "fix."

Prevention

  • Fix prompt template: "minimal change; no refactors; no new deps; no file moves."
  • Quality gate: workflow/threshold edits forbidden in fix PRs (Quality Gates).
  • Human rejects oversized fix PRs — split or redo.

Recovery prompt

text
This fix drifted out of scope. Revert all changes not required
to make <failing test / repro> pass. No refactors, no renames,
no dependency changes, no doc rewrites unless the bug is wrong
docs.

Show the minimal diff. If you believe a larger change is
required, stop and explain without implementing it.

Review checklist

  • [ ] Diff size proportional to the bug
  • [ ] No new deps / structural moves
  • [ ] Regression test added; nothing else "improved"
  • [ ] Edge cases not deleted to achieve green

Decision: continue vs kill the session

SignalAction
First failure, new evidence availableContinue once with an instrumented experiment
Second failure, same hypothesisKill loop; write evidence file; fresh session
Working tree oscillatingReset to last good; narrow mandate
Agent wants to "redesign to fix"Stop; that is a new project, not a fix
CI thrash editing workflowsHuman owns gate changes; agent proposes only

A field manual for AI-native software engineering.