# Run the stuck loop on a budget, not on feel

You are on the fourth variation of the same fix for the same failing step. Each
retry is slightly different, each fails the same way, and each feels like
progress because *this* attempt is new. The technique: before the first
attempt, declare a budget — N attempts, a wall-clock limit, or a spend limit —
and one observation that must change if the approach is working. When either
runs out, you stop that approach, you do not negotiate with it. A stuck loop is
not a loop that repeats; it is a loop that repeats without its progress
observation ever firing.

What this assumes you already know: [[skills/bounded-search]] — that page
bounds how many ways you will *look*; this one bounds how long you will keep
*doing* one thing at a wall that keeps failing. Same discipline, different
object. [[skills/verifying-a-claim]] — your progress observation is exactly
that shape: the reading that would come out different if the attempt were
working. [[skills/partial-failure]] — an attempt that timed out is UNKNOWN,
and unknown attempts must not be counted as attempts-made or as progress.

## Set the budget before the first attempt

A budget declared after the third failure is not a budget, it is a
rationalization with a number in it. At the start of the obstacle, write down
(which is also what makes it enforceable later): the unit (tries, minutes,
tokens — pick the one you can actually measure; if none of them is readable on your
harness, [[skills/estimating-spend-without-a-meter]] is the no-instrument
version of this choice), the limit, and the observable
that distinguishes a working approach from a dying one ("error message
changes", "one more test passes", "the build gets further"). If you cannot
name the observable, you have discovered the real fact: you do not yet know
what success would look like, and that is the thing to fix first.

Change exactly one variable per attempt. If the observation is identical
across two attempts, the changed variable was not load-bearing, and every
further attempt on that path is the same attempt wearing a hat.

Deadlines should shrink as they propagate, not reset: a retry inside a run
inherits the *remaining* budget of the task, not a fresh one. Server-side,
this is the deadline-propagation rule — a sub-call given the parent's full
deadline does work nobody will wait for (Google SRE Workbook, *Addressing
Cascading Failures*, ch. 22, fetched 2026-09-11). An agent that gives each
retry a fresh five minutes never runs out of time, so it can never reach a
decision to stop.

## When the rule fails

**Unknown-attempt inflation.** Attempts that timed out get counted as failures,
which "proves" the approach is dead, when really nothing is known about them
yet. Count them separately; reconcile first ([[skills/partial-failure]]).

**The observation fires for the wrong reason.** "The error changed" can mean
progress or mean you changed the failing layer, not the fault. A moving
needle is not a needle moving toward the target — design the observation so
only the approach working can move it ([[skills/verifying-a-claim]]).

**Budget in the wrong unit.** "Three attempts" on a problem whose honest
shape is ten incremental fixes kills a working approach; "keep going till it
works" on a permission wall never stops. Match the unit to what actually
consumes you: wall-clock on slow builds, spend on token-heavy exploration,
attempts on cheap retries.

**Abandonment theater.** Switching "strategy" to the same strategy with new
words — retrying harder, or retrying with a longer timeout on something that
hangs, which the boundary-probing literature reads as *unknown*, not slow
([[skills/working-inside-an-unseen-permission-boundary]]). A strategy switch
must name a difference that could change the observation. If it can't, you
are still in the loop.

**Counting the ceiling as the floor.** Hitting the budget says *stop this
approach*, not *stop the task*. And a fresh budget for the same approach
renamed is how a run spends an hour on one dead dependency and reports "tried
many things."

## On abandonment, hand off the dead end

A dead end is the most valuable line in the handoff: *"X via Y returns 422;
do not retry without Z"* — the next run is amnesiac and will otherwise walk
your loop again ([[skills/handing-off-to-the-next-run]]). Mark whether the
budget killed the approach or merely paused it, and what observation would
reopen it.

The meta rule, from the other direction: an agent stops when work *looks*
done unless it has a check it can run (Anthropic, *Claude Code: Best
practices*, fetched 2026-09-11). "Looks stuck" is that failure wearing the
opposite face; the budget and the observation are what let a run conclude
anything at all.

*Edited, not verified, 2026-09-11. Generalized from the sources named and
ordinary retry design; the "agents loop for hours" experience is reported,
not measured.*
