fix(worker): propagate unit-merge failures instead of reporting success
A child merge that came back blocked/verify_failed/untracked_collision during a parent/children unit merge used to vanish: DrainAsync only logged it server-side, PlanningMergeAborted carried no reason, and ApproveReview/review_task always reported StatusMerged for a task with children regardless of the real outcome, so a failed unit merge left the parent stuck with no visible error. - PlanningMergeOrchestrator.StartAsync/ContinueAsync/DrainAsync now return a PlanningMergeResult(Status, Reason) instead of void, and PlanningMergeAborted carries that reason to the UI. - WorkerHub.ApproveReview and ExternalMcpService.ReviewTask's approve branch propagate the real status/reason for a parent with children instead of hardcoding "merged" (or masking a non-conflict failure as "conflict"). - StartAsync now requires the parent to already be WaitingForReview for improvement parents too, not just planning ones, so a stale caller can no longer trigger a partial child merge. - HasActiveMerge now also covers the window between the last child merging and FinalizeParentDoneAsync completing, closing a gap where a concurrent Cancel could race the parent's own approve-to-Done transition. - IslandsShellViewModel.OnPlanningMergeAborted flashes the reason via FlashFooterError instead of only clearing the external-merge banner.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Ui.ViewModels;
|
||||
using Xunit;
|
||||
|
||||
@@ -43,6 +44,31 @@ public class IslandsShellViewModelExternalMergeTests
|
||||
Assert.False(vm.IsExternalMergeBannerVisible);
|
||||
}
|
||||
|
||||
// Covers the unit-merge-error-propagation fix: a real merge failure (blocked/verify_failed/
|
||||
// untracked_collision) reaches the UI as a reason on PlanningMergeAborted, and must surface
|
||||
// in the footer strip rather than silently vanishing once the banner is cleared.
|
||||
[Fact]
|
||||
public void Aborted_WithReason_FlashesFooterError()
|
||||
{
|
||||
var vm = new IslandsShellViewModel();
|
||||
|
||||
vm.OnPlanningMergeAborted("plan1", "child merge blocked: unrelated histories");
|
||||
|
||||
Assert.Equal(WorkerLogLevel.Error, vm.WorkerLogLevel);
|
||||
Assert.Contains("child merge blocked: unrelated histories", vm.WorkerLogText);
|
||||
Assert.True(vm.IsWorkerLogVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Aborted_WithoutReason_DoesNotFlashFooterError()
|
||||
{
|
||||
var vm = new IslandsShellViewModel();
|
||||
|
||||
vm.OnPlanningMergeAborted("plan1", null);
|
||||
|
||||
Assert.False(vm.IsWorkerLogVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Completed_ClearsBanner()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user