Context
PR #3940 restores the task_workspace_lifecycle tool (reversible archive/unarchive of owned workspace-turn workspaces). Its interrupt_active option interrupts active turns before archiving, but delegated turns are exempted from the "queued user messages" refusal only while their durable handle reports status === "queued".
Problem (Codex review round 15, P2)
When a newly created delegated workspace turn is in AgentSession's PREPARING phase:
- the durable handle is already
running, and
hasPendingQueuedOrPreparingTurn() makes listLiveWorkspaceActivity().queuedMessages true.
Because the exemption only recognizes status === "queued", the archive request classifies the PREPARING turn as unrelated queued user activity and returns status: "active" even with interrupt_active: true. The documented interruption path is therefore refused during every delegated turn's startup window (it becomes usable again once the turn starts streaming).
This is fail-safe (over-refusal, no data loss) but makes interrupt_active transiently unusable and forces callers to retry.
Suggested direction
Distinguish a PREPARING delegated turn owned by the target (interruptible: it has a delegated workspace-turn handle that interrupt_active is allowed to stop) from an unrelated queued user message (must refuse). Likely requires exposing which pending/preparing entries belong to delegated turn dispatch vs. user-queued messages, and extending the exemption accordingly — with care not to reopen the queued-message races closed in earlier review rounds (turn admission hold, synchronous send guards).
References
Generated with mux • Model: anthropic:claude-fable-5 • Thinking: xhigh
Context
PR #3940 restores the
task_workspace_lifecycletool (reversiblearchive/unarchiveof owned workspace-turn workspaces). Itsinterrupt_activeoption interrupts active turns before archiving, but delegated turns are exempted from the "queued user messages" refusal only while their durable handle reportsstatus === "queued".Problem (Codex review round 15, P2)
When a newly created delegated workspace turn is in AgentSession's PREPARING phase:
running, andhasPendingQueuedOrPreparingTurn()makeslistLiveWorkspaceActivity().queuedMessagestrue.Because the exemption only recognizes
status === "queued", the archive request classifies the PREPARING turn as unrelated queued user activity and returnsstatus: "active"even withinterrupt_active: true. The documented interruption path is therefore refused during every delegated turn's startup window (it becomes usable again once the turn starts streaming).This is fail-safe (over-refusal, no data loss) but makes
interrupt_activetransiently unusable and forces callers to retry.Suggested direction
Distinguish a PREPARING delegated turn owned by the target (interruptible: it has a delegated workspace-turn handle that
interrupt_activeis allowed to stop) from an unrelated queued user message (must refuse). Likely requires exposing which pending/preparing entries belong to delegated turn dispatch vs. user-queued messages, and extending the exemption accordingly — with care not to reopen the queued-message races closed in earlier review rounds (turn admission hold, synchronous send guards).References
TaskService.archiveOwnedWorkspaceTurnWorkspace/collectActiveWorkspaceLifecycleTurns(src/node/services/taskService.ts)WorkspaceService.listLiveWorkspaceActivity(src/node/services/workspaceService.ts)Generated with
mux• Model:anthropic:claude-fable-5• Thinking:xhigh