Skip to content

Delete the re-read thrash hard stop (CL-6936) - #558

Merged
TheGreatAxios merged 1 commit into
mainfrom
cl-6936-re-read-thrash-hard-stop-at-rereadlimit-4-false-positives-on
Aug 23, 2026
Merged

Delete the re-read thrash hard stop (CL-6936)#558
TheGreatAxios merged 1 commit into
mainfrom
cl-6936-re-read-thrash-hard-stop-at-rereadlimit-4-false-positives-on

Conversation

@TheGreatAxios

@TheGreatAxios TheGreatAxios commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Closes CL-6936.

reReadLimit: 4 hard-stopped a worker after four reads of one path (or four identical greps) past 8 total tool calls, reported as thrash — a HARD_BLOCK_SALVAGES class, so sticky for the session and refusing identical re-dispatch. Read pressure only decayed when a product mutation tool edited that exact path, so all of these tripped it on healthy work:

  • read file A four times while editing file B (no decay, A was never edited)
  • four whole-file reads of one file at four different moments in a long task
  • re-running the same grep after an edit — ordinary verify-after-change

Justification, corrected after review

The original framing here claimed this stop was redundant with detectToolFingerprintThrash. That is not true, and the PR should not rest on it: that function's only consumer is the primary director (src/agent/director.ts), leaf workers never call it, and its history excludes any turn carrying text. A leaf reading A,B,A,C,A — or narrating between reads — was caught by the deleted counter and is caught by nothing now except the turn budget.

The honest justification is that the population this counter could legitimately catch barely exists. A scan of 3,796 local runs found 466 clusters of 4+ reads on one path:

  • 97.0% were chunked pagination — distinct (offset, limit) windows of one large file, forced by our own 80k result cap telling the model to paginate (filed as CL-6961). These never tripped this counter, since readKey already keyed chunked reads separately.
  • 1.9% were an identical re-read after editing that path — model-initiated verification the harness already performs invisibly (filed as CL-6962).
  • 1.1% were identical repeats with no edit between, and the worst case in the corpus came from an adversarial eval fixture rather than organic work.

So the counter's real target is a fraction of a percent of runs, mostly synthetic, while its cost was a sticky hard block on healthy workers. Deleting it and leaving the turn budget as the backstop is the right trade. Building leaf-side cycle detection for that population would be paying architecture for a rounding error; if it is ever wanted, the cheap version is to reuse the compactor's path+offset+limit read identity rather than counting paths.

Deleted rather than retuned: detectToolFingerprintThrash already catches a genuinely repeating read cycle, on the evidence that it repeats. A raw count cannot separate four reads across real progress from four reads in a loop, and its verdict is the more severe of the two.

What changed

  • thrash.ts keeps near-budget report-forced plus the read/edit bookkeeping requireEdit / requireEvidence consume. reReadLimit / reReadSoftLimit / reReadMinTotalTools, thrashFromReRead, thrashSoftReRead are gone.
  • Edit-decay of read counts is gone with them. readCounts is now the requireEvidence record, so an edit erasing read evidence could only ever weaken that check.
  • "thrash" and "re-read-nudge" leave SubAgentStopReason / ForcedStopReason, forcedStopReport, and the SubAgentDirector wiring (RE_READ_NUDGE_*, reReadNudgeFired).
  • The progressive thrash Summary-substring classifier in brief-dispatch.ts is deliberately left in place — CL-6939 owns the matcher deletions.
  • ARCHITECTURE / PRODUCT / CHANGELOG updated in the same diff.

Net -487 lines with no coverage loss on the surviving behavior.

Verification

bun run check green: 5262 pass / 0 fail across 377 files.

Improvement in false-positive rate cannot be measured until CL-6938 lands — that is the gate on claiming an improvement, not on making the deletion (redundancy is the justification here, and no threshold was changed).

Review

needs-sawyer-review — Guardrail 4: touches stop/nudge policy. Not for auto-merge. Per eval policy this diff materially touches stop/nudge policy, so it wants an eval matrix run before merge.


Review fix applied: docs/PRODUCT.md still listed "thrash" in the same-brief hard-block salvage list; this branch deleted the thrash hard stop so nothing produces that salvage anymore. Dropped "thrash / " from the sentence.

@linear-code

linear-code Bot commented Aug 23, 2026

Copy link
Copy Markdown

CL-6936

@TheGreatAxios
TheGreatAxios force-pushed the cl-6936-re-read-thrash-hard-stop-at-rereadlimit-4-false-positives-on branch from 055690c to 928447d Compare August 23, 2026 19:49
reReadLimit 4 hard-stopped a worker for reading one path four times past
8 total tool calls, reported as thrash — a sticky hard block that refuses
identical re-dispatch. Read pressure only decayed when a product mutation
tool edited that exact path, so reading file A while editing file B, four
whole-file reads spread across a long task, and re-running a grep to
verify an edit all tripped it on healthy work.

The fingerprint period detector in stop-policy.ts already catches a
genuinely repeating read cycle, and catches it on the evidence that it
repeats rather than on a raw count. Re-read counting is strictly weaker
and its verdict is more severe, so this deletes it rather than retuning
the number.

- thrash.ts keeps only near-budget force-report plus the read/edit
  bookkeeping that requireEdit / requireEvidence consume; the edit-decay
  of read counts goes too, since an edit erasing read evidence could only
  ever weaken the requireEvidence check.
- "thrash" and "re-read-nudge" leave SubAgentStopReason/ForcedStopReason
  and the SubAgentDirector wiring; the Summary-substring classifier in
  brief-dispatch.ts is left for CL-6939.

Net -487 lines.
@TheGreatAxios
TheGreatAxios force-pushed the cl-6936-re-read-thrash-hard-stop-at-rereadlimit-4-false-positives-on branch from 928447d to d9efb08 Compare August 23, 2026 19:57
@TheGreatAxios
TheGreatAxios merged commit 72281a1 into main Aug 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant