fix(ui): gate queueing on an open interactive ConPTY session

A task-based ConPTY session leaves the row Idle in the DB (sessions never
touch status), so nothing stopped the queue picker from claiming it too:
CanSendToQueue ignored HasInteractiveSession, and both TasksIslandViewModel.
SendToQueueAsync and MissionControlViewModel.EnqueueTaskAsync (drag-to-queue)
wrote Status=Queued straight via EF, bypassing TaskStateService entirely and
its manual/draft-child guards. That let an autonomous claude process spawn in
the same worktree a user was hand-editing in the ConPTY pane.

Add !HasInteractiveSession to CanSendToQueue, and route both UI enqueue paths
through IWorkerClient.SetTaskStatusAsync (worker hub -> TaskStateService.
EnqueueAsync) instead of raw EF writes. The interactive-session gate itself
stays in the UI: the worker has no notion of a UI-hosted ConPTY pane.
This commit is contained in:
mika kuns
2026-08-06 13:29:44 +02:00
parent 0d1e3b9a6f
commit d84607f796
8 changed files with 111 additions and 33 deletions
@@ -87,6 +87,21 @@ public class TaskRowViewModelPlanningTests
Assert.True(vm.CanSendToQueue);
}
[Fact]
public void OpenInteractiveSession_CannotSendToQueue()
{
// A hand-driven ConPTY session is still Idle in the DB (sessions never touch status), so
// this has to be gated on the UI-only HasInteractiveSession flag, not on Status.
var vm = MakeRow(TaskStatus.Idle);
Assert.True(vm.CanSendToQueue);
vm.HasInteractiveSession = true;
Assert.False(vm.CanSendToQueue);
vm.HasInteractiveSession = false;
Assert.True(vm.CanSendToQueue);
}
[Fact]
public void FinalizedParentWithChildren_CanQueuePlan()
{