Approve & Merge is now the only review+merge entry. For a parent with
children it drives the unit merge via the worker (conflicts still surface
through the existing PlanningMergeConflict dialog); the separate Merge All
Subtasks button, MergeAllCommand, CanMergeAll plumbing, and the dead
MergeAllPlanningAsync client method are removed. Combined-diff preview and
conflict continue/abort are kept.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Details island review commands (Approve/Reject/Park/Cancel) invoked the
hub without catching exceptions. After "Merge all" folds the parent out of
WaitingForReview, pressing Approve made the hub throw a HubException, which
escaped the generated AsyncRelayCommand as an unobserved async-void exception
and crashed the app. Wrap the calls in try/catch like the Tasks island does;
the TaskUpdated broadcast reconciles the UI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a StubWorkerClient base implementing the full IWorkerClient surface so
the planning/conflict/diff test fakes only override the members they exercise.
Eliminates the constructor-drift duplication across the three fakes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The IWorkerClient.ListUpdatedEvent member was added without updating three
test fakes, breaking compilation of the Ui.Tests project.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three behavioral changes around stuck planning subtasks:
- OrphanRecovery no longer clears ParentTaskId. Queued children of a
parent that is not in a planning phase are dequeued (Status: Queued
-> Idle, BlockedByTaskId cleared) but stay attached to the parent so
the historical lineage is preserved.
- DiscardPlanningAsync stops promoting terminal (Done/Failed/Cancelled)
children to top-level for the same reason - they remain ChildTasks of
the (now non-planning) parent.
- New PlanningLineageRecovery hosted service scans
~/.todo-app/planning-sessions/ and re-attaches a single, unambiguous
blocked-by chain to its original planning parent when the
parent_task_id links were lost. Refuses to guess when multiple
candidate chains exist.
UI now exposes ConnectionRestoredEvent on IWorkerClient, fired on first
connect and every reconnect. ListsIslandViewModel refreshes counters
and TasksIslandViewModel reloads the current list - so stale counts no
longer survive a worker restart.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three coordinated guards close the orphan-creation paths:
- CreateChildAsync refuses when the parent is not in a planning phase.
- DiscardPlanningAsync now returns a structured DiscardPlanningOutcome
and refuses when children are queued or running; callers can opt into
auto-dequeuing queued kids via dequeueQueuedChildren=true. Terminal
children (Done/Failed/Cancelled) are promoted to top-level instead of
becoming orphans when the parent's PlanningPhase is reset.
- OrphanRecovery hosted service clears ParentTaskId on any rows whose
parent is missing or no longer in a planning phase on worker startup,
mirroring the StaleTaskRecovery pattern.
UI surfaces the block reason: a confirm dialog offers to dequeue queued
children and retry; a running-children block is shown as a hard error
asking the user to cancel first.
WorkerClient now negotiates the JsonStringEnumConverter so the
DiscardPlanningResult enum round-trips correctly over SignalR.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a status ComboBox in the Details header (no transition guards)
and a Tags section with chips + AutoCompleteBox. TaskRowViewModel.Tags
becomes an ObservableCollection so chip lists stay live. TasksIsland
caches AllTags for the row context menu and exposes Set/Toggle helpers.
Test fakes updated for the new IWorkerClient methods.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* TaskRepository.UpdateAsync defensively detaches any locally tracked
entity with the same Id before attaching the patched copy, preventing
EF identity conflicts when callers load via AsNoTracking and write
back through the same DbContext (surfaced by ExternalMcpService
UpdateTask integration tests).
* TasksIslandViewModel auto-collapse now only fires for Finalized
planning parents that are not yet Done. Active-phase parents stay
expanded while the user is editing the plan, and Done parents stay
expanded so all completed children land in CompletedItems alongside
the parent.
* Update three Ui.Tests fakes (ConflictResolution, PlanningDiff,
DetailsIslandPlanning) to implement the two new IWorkerClient
members (OpenInteractiveTerminalAsync, QueuePlanningSubtasksAsync).
* Rewrite StreamLineFormatterTests to exercise the current
assistant/user/result/system message format instead of the legacy
stream_event parsing that was removed in the formatter rewrite.
* Align AppSettingsRepository seed-default assertion with the
permission-mode default that flipped from bypassPermissions to auto.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Slice 6 of the worker state and queue consolidation refactor.
* Drop Manual, Planning, Planned, Draft, Waiting from the TaskStatus enum
and from the EF value converter; only the lifecycle values remain
(Idle, Queued, Running, Done, Failed, Cancelled).
* Add migration RetireLegacyTaskStatus that rewrites existing rows:
manual/draft -> idle, planning -> idle+planning_phase=active,
planned -> idle+planning_phase=finalized, waiting -> queued+blocked_by
derived from sort_order via a CTE with LAG().
* Reroute every call site that compared/set legacy values to the new
three-field model (Status + PlanningPhase + BlockedByTaskId), including
the planning repo helpers, MCP services, the planning chain coordinator,
and the UI view-models. TaskRowViewModel now exposes PlanningPhase to
drive the planning badge.
* Refresh Worker/CLAUDE.md and Data/CLAUDE.md, the docs/plan.md status
section, and the planning verification notes in docs/open.md.