From e2c89dbc145783c72a160dbbb4dd5230fbc7a543 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Wed, 22 Apr 2026 04:46:34 +0000 Subject: [PATCH] fix(runtime): correct unverified-write state transitions in mixed verify/write turns Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com> --- internal/runtime/turn_control.go | 22 +++++++++++++--- internal/runtime/turn_control_test.go | 36 +++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/internal/runtime/turn_control.go b/internal/runtime/turn_control.go index 6424de05..768f71ff 100644 --- a/internal/runtime/turn_control.go +++ b/internal/runtime/turn_control.go @@ -32,11 +32,25 @@ func collectCompletionState( // applyToolExecutionCompletion 更新一轮工具执行后的 completion 事实。 func applyToolExecutionCompletion(current controlplane.CompletionState, summary toolExecutionSummary) controlplane.CompletionState { - if summary.HasSuccessfulWorkspaceWrite { - current.HasUnverifiedWrites = true + if len(summary.Results) == 0 { + if summary.HasSuccessfulWorkspaceWrite { + current.HasUnverifiedWrites = true + } + if summary.HasSuccessfulVerification { + current.HasUnverifiedWrites = false + } + return current } - if summary.HasSuccessfulVerification { - current.HasUnverifiedWrites = false + for _, result := range summary.Results { + if result.IsError { + continue + } + if result.Facts.WorkspaceWrite { + current.HasUnverifiedWrites = true + } + if result.Facts.VerificationPerformed && result.Facts.VerificationPassed { + current.HasUnverifiedWrites = false + } } return current } diff --git a/internal/runtime/turn_control_test.go b/internal/runtime/turn_control_test.go index 81c87442..93a1d7cf 100644 --- a/internal/runtime/turn_control_test.go +++ b/internal/runtime/turn_control_test.go @@ -28,20 +28,52 @@ func TestApplyToolExecutionCompletionTracksWriteAndVerification(t *testing.T) { t.Parallel() written := applyToolExecutionCompletion(controlplane.CompletionState{}, toolExecutionSummary{ - HasSuccessfulWorkspaceWrite: true, + Results: []tools.ToolResult{ + {Facts: tools.ToolExecutionFacts{WorkspaceWrite: true}}, + }, }) if !written.HasUnverifiedWrites { t.Fatalf("expected successful write to require verification, got %+v", written) } verified := applyToolExecutionCompletion(written, toolExecutionSummary{ - HasSuccessfulVerification: true, + Results: []tools.ToolResult{ + {Facts: tools.ToolExecutionFacts{VerificationPerformed: true, VerificationPassed: true}}, + }, }) if verified.HasUnverifiedWrites { t.Fatalf("expected explicit verification to clear pending write, got %+v", verified) } } +func TestApplyToolExecutionCompletionKeepsUnverifiedWhenVerifyBeforeWrite(t *testing.T) { + t.Parallel() + + got := applyToolExecutionCompletion(controlplane.CompletionState{}, toolExecutionSummary{ + Results: []tools.ToolResult{ + {Facts: tools.ToolExecutionFacts{VerificationPerformed: true, VerificationPassed: true}}, + {Facts: tools.ToolExecutionFacts{WorkspaceWrite: true}}, + }, + }) + if !got.HasUnverifiedWrites { + t.Fatalf("expected write after verify to remain unverified, got %+v", got) + } +} + +func TestApplyToolExecutionCompletionClearsWhenVerifyAfterWrite(t *testing.T) { + t.Parallel() + + got := applyToolExecutionCompletion(controlplane.CompletionState{}, toolExecutionSummary{ + Results: []tools.ToolResult{ + {Facts: tools.ToolExecutionFacts{WorkspaceWrite: true}}, + {Facts: tools.ToolExecutionFacts{VerificationPerformed: true, VerificationPassed: true}}, + }, + }) + if got.HasUnverifiedWrites { + t.Fatalf("expected verify after write to clear unverified flag, got %+v", got) + } +} + func TestHasPendingAgentTodosBlocksOnAnyNonTerminalTodo(t *testing.T) { t.Parallel()