feat(planning): gate subtask queueing behind plan finalization
Planning subtasks are now "Draft" until their parent plan is finalized, then "Planned" (queueable). Finalizing a plan no longer auto-queues the child chain; the user sends the plan to the queue explicitly. - TaskStateService rejects a child entering Queued/Running unless its parent is Finalized; this single invariant covers UI, queue, RunNow and MCP paths - WorkerHub.SetTaskStatus routes Queued through the gated EnqueueAsync - Finalize call sites pass queueAgentTasks: false - PlanningChainCoordinator.QueuePlanAsync guards the chain build on Finalized - TaskRowViewModel derives Draft/Planned from ParentFinalized; gates CanSendToQueue / CanQueuePlan; view shows a PLANNED badge Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -244,6 +244,16 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
foreach (var r in Items)
|
||||
r.HasQueuedSubtasks = parentsWithQueuedKids.Contains(r.Id);
|
||||
|
||||
// A subtask is "Planned" (queueable) once its planning parent is finalized;
|
||||
// until then it is a "Draft".
|
||||
var finalizedParents = Items
|
||||
.Where(r => r.PlanningPhase == PlanningPhase.Finalized)
|
||||
.Select(r => r.Id)
|
||||
.ToHashSet();
|
||||
foreach (var r in Items)
|
||||
r.ParentFinalized = !string.IsNullOrEmpty(r.ParentTaskId)
|
||||
&& finalizedParents.Contains(r.ParentTaskId!);
|
||||
|
||||
Regroup();
|
||||
UpdateSubtitle();
|
||||
}
|
||||
@@ -645,7 +655,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
await _worker.ResumePlanningSessionAsync(row.Id);
|
||||
break;
|
||||
case UnfinishedPlanningModalResult.FinalizeNow:
|
||||
await _worker.FinalizePlanningSessionAsync(row.Id);
|
||||
await _worker.FinalizePlanningSessionAsync(row.Id, queueAgentTasks: false);
|
||||
break;
|
||||
case UnfinishedPlanningModalResult.Discard:
|
||||
await TryDiscardPlanningWithRetryAsync(row.Id);
|
||||
@@ -713,7 +723,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
|
||||
private async Task FinalizePlanningSessionAsync(TaskRowViewModel? row)
|
||||
{
|
||||
if (row is null) return;
|
||||
try { await _worker!.FinalizePlanningSessionAsync(row.Id, queueAgentTasks: true); }
|
||||
try { await _worker!.FinalizePlanningSessionAsync(row.Id, queueAgentTasks: false); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user