ParseOp only covered LoadFilesAsync; OnDisplayedDiffChanged's parse (driven
by ToggleCombinedAsync and OnSelectedSubtaskChanged) had no visible
feedback even though the offload was already correct. Both call sites now
go through one ParseOffUiThreadAsync helper (Begin on the UI thread before
Task.Run, End via `using` regardless of a stale generation), so the
already-visible toolbar indicator covers the planning path without
duplicating the begin/offload/end ceremony.
Both call sites (LoadFilesAsync, OnDisplayedDiffChanged) ran the parser
synchronously on the dispatcher, freezing the window on a large diff. The
Files-mode parse+tree-build now runs via Task.Run behind a ParseOp
OperationStatus wired to the toolbar; the planning-mode parse is
fire-and-forget with a generation counter so a fast second DisplayedDiff
change can't write stale PlanningFiles.
TryInvokeAsync catches every exception and returns null, which is fine
for read-only calls but hid real HubException reasons behind a generic
"offline" message for the 7 mutating call sites (RestoreDefaultAgents,
UpsertPrimeSchedule, AddDailyNote, CleanupFinishedWorktrees,
ResetAllWorktrees, ForceRemoveWorktree, BuildPlanningIntegrationBranch)
— the same bug class fixed for ApproveReview in e1807fd. Each of the 22
TryInvokeAsync call sites was audited; the 15 read-only ones are left
unchanged (empty/offline is the right display). For the 7 switched to
a direct hub invoke, every caller was checked and, where it had no
catch, one was added so the exception surfaces (StatusMessage,
ShowErrorAsync/CombinedWarning) instead of crashing.