@@ -810,6 +810,7 @@ func (m *Manager) ResetAgentContext(ctx context.Context, executionID string) err
|
||||
case <-exec.promptDoneCh:
|
||||
default:
|
||||
}
|
||||
exec.dispatchedPromptPending.Store(false)
|
||||
})
|
||||
|
||||
// Restore the complete captured configuration. A strict-mode model that is
|
||||
@@ -1151,6 +1152,7 @@ func (m *Manager) resetAgentRestartState(executionID string, commands agentComma
|
||||
case <-exec.promptDoneCh:
|
||||
default:
|
||||
}
|
||||
exec.dispatchedPromptPending.Store(false)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -250,6 +250,10 @@ func newRestartMockAgentctlServer(t *testing.T, failStop, failSessionNew bool) *
|
||||
"success": true,
|
||||
})
|
||||
}
|
||||
case "agent.prompt":
|
||||
resp, _ = ws.NewResponse(msg.ID, msg.Action, map[string]interface{}{
|
||||
"success": true,
|
||||
})
|
||||
case "agent.stderr":
|
||||
stderrLines := m.stderrLines
|
||||
if len(stderrLines) == 0 {
|
||||
@@ -406,6 +410,7 @@ func TestManager_RestartAgentProcess_Success(t *testing.T) {
|
||||
exec.assistantHistoryBuffer.WriteString("old response")
|
||||
exec.needsResumeContext = true
|
||||
exec.resumeContextInjected = true
|
||||
exec.dispatchedPromptPending.Store(true)
|
||||
exec.promptDoneCh <- PromptCompletionSignal{StopReason: "stale"}
|
||||
|
||||
mgr.executionStore.Add(exec)
|
||||
@@ -443,6 +448,9 @@ func TestManager_RestartAgentProcess_Success(t *testing.T) {
|
||||
t.Fatalf("expected stale prompt signal to be drained")
|
||||
default:
|
||||
}
|
||||
if exec.dispatchedPromptPending.Load() {
|
||||
t.Fatal("expected stale dispatch gate to be cleared")
|
||||
}
|
||||
|
||||
httpActions := mock.getHTTPActions()
|
||||
if !slices.Equal(httpActions, []string{"stop", "configure", "start"}) {
|
||||
@@ -854,6 +862,47 @@ func TestManager_ResetAgentContext_ReappliesSessionMode(t *testing.T) {
|
||||
require.Zero(t, exec.assistantHistoryBuffer.Len())
|
||||
}
|
||||
|
||||
// @covers AC-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002.3
|
||||
func TestManager_ResetAgentContext_ClearsIdleDispatchGate(t *testing.T) {
|
||||
mgr := newTestManager(t)
|
||||
mock := newRestartMockAgentctlServer(t, false, false)
|
||||
|
||||
client := createTestClient(t, mock.server.URL)
|
||||
t.Cleanup(client.Close)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
require.NoError(t, client.StreamUpdates(ctx, func(agentctl.AgentEvent) {}, nil, nil))
|
||||
|
||||
exec := &AgentExecution{
|
||||
ID: "exec-idle-reset",
|
||||
TaskID: "task-1",
|
||||
SessionID: "session-1",
|
||||
AgentProfileID: "profile-1",
|
||||
ACPSessionID: "old-session",
|
||||
AgentCommand: "auggie --model test",
|
||||
Status: v1.AgentStatusRunning,
|
||||
WorkspacePath: "/workspace",
|
||||
sessionInitialized: true,
|
||||
agentctl: client,
|
||||
promptDoneCh: make(chan PromptCompletionSignal, 1),
|
||||
}
|
||||
exec.dispatchedPromptPending.Store(true)
|
||||
exec.promptDoneCh <- PromptCompletionSignal{StopReason: "end_turn"}
|
||||
require.NoError(t, mgr.executionStore.Add(exec))
|
||||
|
||||
require.NoError(t, mgr.ResetAgentContext(ctx, exec.ID))
|
||||
require.False(t, exec.dispatchedPromptPending.Load(),
|
||||
"reset must clear the gate when it drains the completion signal")
|
||||
|
||||
followUpCtx, followUpCancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer followUpCancel()
|
||||
_, err := mgr.PromptAgent(followUpCtx, exec.ID, "follow-up", nil, true)
|
||||
require.NoError(t, err, "follow-up prompt must reach the new agent context")
|
||||
require.Contains(t, mock.getWSActions(), "agent.prompt")
|
||||
}
|
||||
|
||||
// TestManager_ResetAgentContext_ReappliesSessionModel is the regression test
|
||||
// for an ACP fast-path reset replacing the task's selected model with the
|
||||
// provider default from the freshly-created session.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
created: 2026-08-31
|
||||
status: done
|
||||
requirements:
|
||||
- REQ-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002
|
||||
system_design:
|
||||
- ../../specs/tasks/system-design/workflow-step-agent-start-ownership.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation Plan: Clear the Idle Context-Reset Dispatch Gate
|
||||
|
||||
## Overview
|
||||
|
||||
Clear the dispatch-only completion gate when an idle context reset removes its buffered completion signal. Cover the ACP reset path and the process-restart fallback.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Reproduce the idle dispatch-only state in lifecycle manager tests.
|
||||
- Clear `dispatchedPromptPending` after each successful reset path drains `promptDoneCh`.
|
||||
- Prove that the next prompt can reach agentctl after an ACP session reset.
|
||||
- Prove that the process-restart fallback also clears the old gate.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Change the timeout behavior in `waitForPendingDispatchedPrompt`.
|
||||
- Change active-turn quiescence or cancellation ownership.
|
||||
- Add UI recovery for sessions that entered this state before the correction.
|
||||
- Explain unrelated differences between prompt-completion log counts.
|
||||
|
||||
## Technical approach
|
||||
|
||||
Update `Manager.ResetAgentContext` in `manager_interaction.go`. Clear the atomic pending flag in the same locked state update that drains the old completion signal.
|
||||
|
||||
Update `Manager.resetAgentRestartState` in the same file. Apply the same state transition to the process-restart fallback.
|
||||
|
||||
Add focused tests in `manager_interaction_test.go`. The ACP test will reset an idle execution and send a follow-up dispatch-only prompt through the real manager path.
|
||||
|
||||
Extend the existing restart-state test with a pending gate. The test will prove that process replacement clears the signal and its matching flag.
|
||||
|
||||
## Tests
|
||||
|
||||
- `AC-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002.3`: `TestManager_ResetAgentContext_ClearsIdleDispatchGate` proves that the follow-up prompt reaches the new ACP session.
|
||||
- `AC-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002.3`: `TestManager_RestartAgentProcess_Success` proves that the process-restart fallback clears the prior gate.
|
||||
- `AC-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002.5`: Existing pending-wait tests remain unchanged because the timeout still preserves active predecessor ownership.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [x] [Task 01: Clear the idle reset dispatch gate](task-01-clear-idle-reset-dispatch-gate.md)
|
||||
|
||||
## Verification results
|
||||
|
||||
- RED: Both focused regression tests failed because the reset paths kept `dispatchedPromptPending` set.
|
||||
- GREEN: The focused tests passed after both reset paths cleared the flag after the signal drain.
|
||||
- Final: The race-enabled verification passed 2 tests. `git diff --check` also passed.
|
||||
|
||||
## Risks
|
||||
|
||||
- Clearing the gate before the old turn is quiescent can admit concurrent prompts. The existing orchestrator reset boundary must remain unchanged.
|
||||
- Clearing only the ACP fast path leaves adapters that use process replacement exposed to the same error.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
id: "01-clear-idle-reset-dispatch-gate"
|
||||
title: "Clear the idle reset dispatch gate"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002
|
||||
acceptance_criteria:
|
||||
- AC-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002.3
|
||||
- AC-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002.5
|
||||
system_design:
|
||||
- ../../specs/tasks/system-design/workflow-step-agent-start-ownership.md
|
||||
---
|
||||
|
||||
# Task 01: Clear the Idle Reset Dispatch Gate
|
||||
|
||||
## Summary
|
||||
|
||||
Clear the pending dispatch-only gate when a successful idle context reset removes its completion signal. Apply the correction to both provider-reset paths.
|
||||
|
||||
## In scope
|
||||
|
||||
- Add a failing regression test for an idle ACP reset with a buffered dispatch-only completion.
|
||||
- Prove that a follow-up dispatch-only prompt reaches agentctl after the reset.
|
||||
- Add pending-gate coverage to the existing process-restart state test.
|
||||
- Clear the old pending flag after both reset paths drain the old signal.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Clear the gate when `waitForPendingDispatchedPrompt` times out.
|
||||
- Change cancellation escalation or active-turn reset behavior.
|
||||
- Add frontend behavior or browser tests.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- An ACP session reset removes the old completion signal and clears its matching pending flag.
|
||||
- The next prompt reaches agentctl without a predecessor timeout.
|
||||
- The process-restart fallback clears the same signal and flag pair.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
go test -race ./internal/agent/runtime/lifecycle -run 'TestManager_(ResetAgentContext_ClearsIdleDispatchGate|RestartAgentProcess_Success)$' -count=1
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Run the commands from `apps/backend` and the repository root, respectively.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/agent/runtime/lifecycle/manager_interaction.go`
|
||||
- `apps/backend/internal/agent/runtime/lifecycle/manager_interaction_test.go`
|
||||
- `docs/plans/idle-context-reset-dispatch-gate/plan.md`
|
||||
- `docs/plans/idle-context-reset-dispatch-gate/task-01-clear-idle-reset-dispatch-gate.md`
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Risks
|
||||
|
||||
- A reset path that drains the signal without clearing the flag will keep the execution unusable.
|
||||
- A flag clear before successful context replacement can release a valid active generation.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- `REQ-TASKS-WORKFLOW-STEP-AGENT-START-OWNERSHIP-002`
|
||||
- `docs/specs/tasks/system-design/workflow-step-agent-start-ownership.md`
|
||||
- `docs/decisions/2026-08-30-context-reset-quiesces-active-turn.md`
|
||||
- GitHub issue `#3210`
|
||||
- Existing reset and pending-prompt tests in the lifecycle package.
|
||||
|
||||
## Results
|
||||
|
||||
- RED: The focused command failed 2 tests before the production correction.
|
||||
- `TestManager_RestartAgentProcess_Success` found that process replacement kept the stale gate.
|
||||
- `TestManager_ResetAgentContext_ClearsIdleDispatchGate` found the same state after an ACP reset.
|
||||
- GREEN: The focused command passed 2 tests after both reset paths cleared the gate.
|
||||
- Final: The race-enabled verification passed 2 tests. `git diff --check` passed.
|
||||
- Changed files: `manager_interaction.go`, `manager_interaction_test.go`, and this plan package.
|
||||
- No known blockers remain.
|
||||
Reference in New Issue
Block a user