Kill the sticky salvage hard-block's false positives - #579
Merged
TheGreatAxios merged 3 commits intoAug 23, 2026
Merged
Conversation
CL-6936/PR #558 removed the re-read thrash stop, so no report can ever carry a 'progressive thrash' Summary. Remove the now-dead isThrashSubAgentReport/appendThrashParentHint/THRASH_PARENT_HINT in stop-policy.ts, the classifyBriefSalvage thrash branch in brief-dispatch.ts, and the 'thrash' entries in HARD_BLOCK_SALVAGES and BriefSalvageKind. Other salvage kinds are untouched.
Salvage classifiers matched free-text Summary substrings ('no
progress', 'cancelled', etc), so a SUCCESSFUL report whose Summary
happened to contain those words was recorded as a forced stop,
hard-blocking identical re-dispatch. forcedStopReport's summaries are
now a single FORCED_STOP_SUMMARIES lookup shared by both the producer
and the isXxxSubAgentReport classifiers, which compare against it with
exact equality instead of .includes.
A typed marker on the report would need a schema change (CL-6786,
human-gated, out of scope) so this tightens to exact string matching
instead.
Two concurrent identical-brief task calls can both admit. If one salvages and the other succeeds, recordOutcome kept the hard-block lastSalvage sticky through the success, so the failing sibling's sticky block later refused a brief that already produced a good report in the same wave. A successful complete now always clears lastSalvage, since the success itself proves the brief is re-dispatchable.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes CL-6964. Closes CL-6704. Closes CL-6710.
Three related fixes to the sub-agent stop/salvage machinery in
src/subagent/stop-policy.tsandsrc/subagent/brief-dispatch.ts.CL-6964 — delete the unreachable thrash salvage machinery
PR #558 removed the re-read thrash stop, so no report can ever carry a "progressive thrash" Summary anymore. Deleted the now-dead
isThrashSubAgentReport,appendThrashParentHint/THRASH_PARENT_HINT, theclassifyBriefSalvagethrash branch, and the"thrash"entries inHARD_BLOCK_SALVAGES/BriefSalvageKind. Every other salvage kind (no-progress, no-ship, repetition, never-acted, never-edited, turn-budget, deadline, stalled, cancelled, incomplete-report) is untouched.CL-6704 — stop hard-blocking on Summary substrings
The classifiers matched free-text Summary substrings like "no progress" or "cancelled", so a SUCCESSFUL report whose Summary happened to contain those words was recorded as a forced stop — hard-blocking identical re-dispatch and arming primary salvage nudges for work that actually succeeded.
Fixed by making
forcedStopReport's summary strings a singleFORCED_STOP_SUMMARIESlookup, shared with the classifiers viaisForcedStopSubAgentReport, which now compares with exact equality instead of.includes/.toLowerCase().includes. A typed marker would need a report schema change (that's CL-6786, human-gated, left alone) — exact string matching is the fix that fits here.False-positive paths now gone: a successful report whose Summary happens to mention "no progress," "cancelled," "long silence," etc. no longer classifies as any forced-stop salvage.
CL-6710 — clear the sticky block after a parallel sibling succeeds
Two concurrent identical-brief
taskcalls can both admit. If one salvaged and the other succeeded,recordOutcomekept the hard-blocklastSalvagesticky through the success, so the failing sibling's block later refused a brief that had already produced a good report in the same wave.Fixed: a successful complete now always clears
lastSalvage— the success itself proves the brief is re-dispatchable.Regressions added
src/subagent/index.test.ts: successful Summaries containing forced-stop phrases classify asnull(no salvage); true forced-stop strings still classify correctly; parallel admit → salvage + success → next admit allowed.no-progress(the class they were actually generically exercising) since"thrash"is gone fromBriefSalvageKind.Gate
bun run check(lint, typecheck, build, full test suite) green: 5332 pass, 0 fail.