The problem
The stuck-loop steering warning works for about thirty seconds. Then the agent
returns to the very command the warning quoted, repeats it three times in a
row, and the turn is aborted.
nightly-bench has been red on this. The loop gate is right to fail: this is a
real aborted stuck loop, not the misclassification that was already fixed. That
fix is working — see the check at the bottom.
What the trace shows
From the red night of 2026-09-09, run 34336488244, artifact
loop-bench-34336488244, task cobol-modernization, stream
events/cobol-modernization__yV4uZPS.jsonl. Times are from the first event.
At +258.6s the engine detected an exact repeat — the same bash call, three
times consecutively, byte-identical output each time — and emitted a steered
event with aborted: false. The warning named the command and said "vary the
arguments, try a different tool, or report what is blocking you."
The agent then did change strategy. Nine tool calls over the next thirty
seconds, eight of them distinct:
| # |
Time |
Command |
| 1 |
+262.5s |
od -c /app/src/INPUT.DAT |
| 2 |
+267.6s |
the flagged python3 -c reader |
| 3 |
+274.7s |
git diff /app/src/INPUT.DAT |
| 4 |
+277.1s |
git checkout /app/src/INPUT.DAT |
| 5 |
+280.6s |
python3 /app/program.py |
| 6 |
+282.8s |
a different python3 -c reader |
| 7 |
+285.7s |
another different python3 -c reader |
| 8 |
+290.1s |
a text-mode reader |
| 9 |
+292.1s |
the same text-mode reader |
Nothing repeats three times in a row there, so nothing trips the detector.
Then an 86-second gap with no tool call at all, and the agent comes back to
the exact command the warning had quoted:
| # |
Time |
Command |
| 10 |
+378.9s |
the flagged python3 -c reader |
| 11 |
+385.8s |
the same |
| 12 |
+389.5s |
the same |
At +389.5s the detector fires again on the same kind, pattern and
repeats, this time with aborted: true. The turn stops with
DeliberateStopError: Stella exited with code 3. The task scores 0.0.
Why this is worth deciding
The second detection is the same call the first warning quoted by name. Nothing
in the engine remembers that. A call that has already been steered off is
treated on the second pass exactly like a call nobody has ever warned about, so
it gets a fresh three-repeat budget before anything happens — and those three
repeats are what end the turn.
Two directions, and picking between them is a maintainer's call:
- Remember which exact call was steered, and act sooner when it comes back —
abort on the first repeat after a warning rather than the third.
- Leave the threshold alone and make the warning itself do more work.
There may be a third: the 86-second gap before the relapse suggests the warning
fell far enough back in the context to stop steering anything, which would make
this a context-placement question rather than a detector one.
Files
crates/stella-core — loop detection and the steering it emits.
bench/loop-bench/src/lib.rs — the verdict vocabulary and the two counters.
.github/workflows/nightly-bench.yml — the workflow and its pinned task set.
How to reproduce
The artifact is enough to re-read the whole sequence, and costs nothing:
gh api repos/macanderson/stella/actions/artifacts/10098814209/zip > a.zip
unzip a.zip -d lb
# then read lb/events/cobol-modernization__yV4uZPS.jsonl
Reproducing it live needs a bench run, which spends real money. That, plus the
design decision above, is why this is filed rather than fixed.
The earlier fix did not regress
Checked on the same night, both directions:
cobol-modernization — two loop_detected events, one aborted: false and
one aborted: true. The STUCK-LOOP verdict is backed by a real abort.
overfull-hbox — one loop_detected with aborted: false and no
STUCK-LOOP verdict. Its CRASHED row is a harbor timeout at 750s, which is
a separate signal. An unaborted detection on its own no longer produces
STUCK-LOOP, which is exactly what the earlier fix installed.
Which pillar this moves
Reliability. A steering mechanism that the agent walks back into is a loop the
user pays for twice — once in tokens and once in a lost turn.
What done looks like
The problem
The stuck-loop steering warning works for about thirty seconds. Then the agent
returns to the very command the warning quoted, repeats it three times in a
row, and the turn is aborted.
nightly-benchhas been red on this. The loop gate is right to fail: this is areal aborted stuck loop, not the misclassification that was already fixed. That
fix is working — see the check at the bottom.
What the trace shows
From the red night of 2026-09-09, run 34336488244, artifact
loop-bench-34336488244, taskcobol-modernization, streamevents/cobol-modernization__yV4uZPS.jsonl. Times are from the first event.At +258.6s the engine detected an exact repeat — the same
bashcall, threetimes consecutively, byte-identical output each time — and emitted a
steeredevent with
aborted: false. The warning named the command and said "vary thearguments, try a different tool, or report what is blocking you."
The agent then did change strategy. Nine tool calls over the next thirty
seconds, eight of them distinct:
od -c /app/src/INPUT.DATpython3 -creadergit diff /app/src/INPUT.DATgit checkout /app/src/INPUT.DATpython3 /app/program.pypython3 -creaderpython3 -creaderNothing repeats three times in a row there, so nothing trips the detector.
Then an 86-second gap with no tool call at all, and the agent comes back to
the exact command the warning had quoted:
python3 -creaderAt +389.5s the detector fires again on the same
kind,patternandrepeats, this time withaborted: true. The turn stops withDeliberateStopError: Stella exited with code 3. The task scores 0.0.Why this is worth deciding
The second detection is the same call the first warning quoted by name. Nothing
in the engine remembers that. A call that has already been steered off is
treated on the second pass exactly like a call nobody has ever warned about, so
it gets a fresh three-repeat budget before anything happens — and those three
repeats are what end the turn.
Two directions, and picking between them is a maintainer's call:
abort on the first repeat after a warning rather than the third.
There may be a third: the 86-second gap before the relapse suggests the warning
fell far enough back in the context to stop steering anything, which would make
this a context-placement question rather than a detector one.
Files
crates/stella-core— loop detection and the steering it emits.bench/loop-bench/src/lib.rs— the verdict vocabulary and the two counters..github/workflows/nightly-bench.yml— the workflow and its pinned task set.How to reproduce
The artifact is enough to re-read the whole sequence, and costs nothing:
Reproducing it live needs a bench run, which spends real money. That, plus the
design decision above, is why this is filed rather than fixed.
The earlier fix did not regress
Checked on the same night, both directions:
cobol-modernization— twoloop_detectedevents, oneaborted: falseandone
aborted: true. TheSTUCK-LOOPverdict is backed by a real abort.overfull-hbox— oneloop_detectedwithaborted: falseand noSTUCK-LOOPverdict. ItsCRASHEDrow is a harbor timeout at 750s, which isa separate signal. An unaborted detection on its own no longer produces
STUCK-LOOP, which is exactly what the earlier fix installed.Which pillar this moves
Reliability. A steering mechanism that the agent walks back into is a loop the
user pays for twice — once in tokens and once in a lost turn.
What done looks like
repeat budget when it recurs.
passes on the new one.
nightly-benchrun on the change shows thecobol-modernizationstream either not relapsing or aborting sooner, read from its own
artifact rather than from the verdict table.