Skip to content

Commit 4e33f35

Browse files
committed
Raise leaf no-progress repeat limit from 2 to 5
Two identical tool-call fingerprints hard-stopped a leaf worker on legitimate polling (rerunning a flaky test, checking a build). The director-level thrash threshold already sits at 5 for the same forensic reason (CL-5611: a prior 4-repeat pause false-positived on this exact pattern), so mirror it here instead of stopping at 2. Fixes CL-6776 https://linear.app/abklabs/issue/CL-6776
1 parent dba0d3f commit 4e33f35

2 files changed

Lines changed: 43 additions & 5 deletions

File tree

src/subagent/index.test.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,41 @@ describe("sub-agent stop helpers", () => {
162162
});
163163

164164
test("no-progress trips at the default repeat limit", () => {
165-
expect(DEFAULT_SUBAGENT_REPEAT_LIMIT).toBe(2);
166-
expect(subAgentNoProgress(1, DEFAULT_SUBAGENT_REPEAT_LIMIT)).toBe(false);
167-
expect(subAgentNoProgress(2, DEFAULT_SUBAGENT_REPEAT_LIMIT)).toBe(true);
165+
expect(DEFAULT_SUBAGENT_REPEAT_LIMIT).toBe(5);
166+
expect(subAgentNoProgress(4, DEFAULT_SUBAGENT_REPEAT_LIMIT)).toBe(false);
167+
expect(subAgentNoProgress(5, DEFAULT_SUBAGENT_REPEAT_LIMIT)).toBe(true);
168+
});
169+
170+
test("legitimate polling (2-4 identical fingerprints) does not hard-stop (CL-6776)", () => {
171+
// A worker rerunning `git status` or polling a build a few times while
172+
// waiting must not be hard-blocked on identical re-dispatch.
173+
for (const consecutive of [2, 3, 4]) {
174+
expect(subAgentNoProgress(consecutive, DEFAULT_SUBAGENT_REPEAT_LIMIT)).toBe(false);
175+
expect(
176+
evaluateSubAgentStop({
177+
hasToolCalls: true,
178+
everHadToolCalls: true,
179+
turnsCompleted: consecutive,
180+
maxTurns: DEFAULT_SUBAGENT_MAX_TURNS,
181+
consecutiveIdentical: consecutive,
182+
repeatLimit: DEFAULT_SUBAGENT_REPEAT_LIMIT,
183+
}),
184+
).toBeNull();
185+
}
186+
});
187+
188+
test("a true runaway (>5 identical fingerprints) still hard-stops", () => {
189+
expect(subAgentNoProgress(6, DEFAULT_SUBAGENT_REPEAT_LIMIT)).toBe(true);
190+
expect(
191+
evaluateSubAgentStop({
192+
hasToolCalls: true,
193+
everHadToolCalls: true,
194+
turnsCompleted: 6,
195+
maxTurns: DEFAULT_SUBAGENT_MAX_TURNS,
196+
consecutiveIdentical: 6,
197+
repeatLimit: DEFAULT_SUBAGENT_REPEAT_LIMIT,
198+
}),
199+
).toBe("no-progress");
168200
});
169201

170202
test("fingerprint is null when a turn has no tool calls", () => {

src/subagent/stop-policy.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ import {
1818
parseSubAgentReport,
1919
} from "./report.js";
2020

21-
/** Consecutive identical tool-call fingerprints before a leaf is forced to stop. */
22-
export const DEFAULT_SUBAGENT_REPEAT_LIMIT = 2;
21+
// Consecutive identical tool-call fingerprints before a leaf is forced to
22+
// stop. Mirrors IDENTICAL_REPEAT_MIN below (the director-level period-1
23+
// thrash threshold): the same forensic scan found zero occurrences of even
24+
// two consecutive identical fingerprints in local trace history, and CL-5611
25+
// found the previous 4-repeat hard pause false-positived on legitimate
26+
// polling (rerunning a flaky test, polling a build) — hence a threshold set
27+
// above 4, not at 2.
28+
export const DEFAULT_SUBAGENT_REPEAT_LIMIT = 5;
2329

2430
// Minimum gap kept between an opt-in internal deadline and the outer
2531
// tool-execution watchdog, so there is time left for the salvage report to

0 commit comments

Comments
 (0)