Stop readiness permission loops / 阻止 readiness 权限循环#6073
Merged
SivanCola merged 2 commits intoJul 6, 2026
Conversation
- Replace the readiness loop-guard text scan with host state armed by the storm breaker itself: a guard on any result of a multi-call batch now unlocks the final blocker report, and tool output that merely quotes "[loop guard]" no longer does. - Keep the pass across the bookkeeping the guard recommends (ask, todo_write, complete_step); revoke it once a successful write or command receipt proves receipts are obtainable again. - Add a blocked-turn streak detector so rotating tools, reordering batches, or blockers whose text varies per attempt still trip the guard after three consecutive fully-blocked turns.
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.
Summary
Cache-impact: low - Only recovery-turn synthetic guidance and loop-guard result text change; system prompt, tool schemas, tool ordering, provider request serialization, and compaction behavior are unchanged.
Cache-guard: scripts/check-cache-impact.sh metadata gate;
go test ./internal/agent -run 'TestFinalReadinessPermissionLoopGuardAllowsBlockedFinal|TestFinalReadinessPermissionLoopGuardAllowsBlockedFinalForBatch|TestStormBreakerEscalatesRepeatedBlockedPermission|TestStormBreakerEscalatesAlternatingBlockedShapes|TestStormBreakerBlockedStreakResetBySuccess|TestFinalReadinessAllowsFinalAfterLoopGuardedToolBlocker|TestFinalReadinessLoopGuardPassSurvivesBookkeeping|TestFinalReadinessLoopGuardPassRevokedByRealProgress|TestFinalReadinessIgnoresLoopGuardQuotedInToolOutput';go test ./internal/evidence -run 'TestLedgerHasWriteOrCommandSince';go test ./internal/agent ./internal/permission ./internal/control;go test ./...;git diff --check.Problem and cause
After a write plus
todo_write, final-answer readiness blocks a final response until host-observable receipts prove the work is complete. If the model tries to satisfy that by runningbash, a permission denial, plan-mode refusal, or hook block returns ablocked:tool result.The previous storm breaker ignored blocked outcomes, so each changed command or argument reset loop detection even when every attempt hit the same host refusal. In practice this could surface as repeated bash approval requests while the task never completed. After a loop guard did appear, final-readiness could still ask for receipts that could no longer be produced, causing another retry instead of letting the model report the blocker.
Review of the first iteration found three residual gaps in its "latest tool result contains
[loop guard]" detection:[loop guard](a grep over this repo, a pasted transcript) unlocked readiness by accident.ask,todo_write,complete_step) made a newer tool result the latest one, revoking the pass and restarting the retry loop. Separately, a model rotating between two blocked shapes reset the signature detector every turn and never tripped the guard at all.Fix
Ledger.Len/Ledger.HasWriteOrCommandSince).complete_stepandtodo_writefrom existing receipts and does not run exploratory bash commands just to satisfy readiness.Tests
go test ./internal/agent -run 'TestFinalReadinessPermissionLoopGuardAllowsBlockedFinal|TestFinalReadinessPermissionLoopGuardAllowsBlockedFinalForBatch|TestStormBreakerEscalatesRepeatedBlockedPermission|TestStormBreakerEscalatesAlternatingBlockedShapes|TestStormBreakerBlockedStreakResetBySuccess|TestFinalReadinessAllowsFinalAfterLoopGuardedToolBlocker|TestFinalReadinessLoopGuardPassSurvivesBookkeeping|TestFinalReadinessLoopGuardPassRevokedByRealProgress|TestFinalReadinessIgnoresLoopGuardQuotedInToolOutput'go test ./internal/evidence -run 'TestLedgerHasWriteOrCommandSince'go test ./internal/agent ./internal/permission ./internal/controlgo test ./...git diff --check