fix(worker): mark task Done on every successful merge path, not just approve

Generalizes the previous merge_task fix: the WaitingForReview->Done transition
now lives in TaskMergeService.MergeAsync/ContinueMergeAsync, so the UI Merge
button (WorkerHub.MergeTask), conflict-merge, continue-merge and the external
MCP all land a merged task in Done. ApproveAndMergeAsync no longer double-approves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-06-09 10:41:08 +02:00
parent ca8326c4c5
commit f56cc617c3
2 changed files with 14 additions and 13 deletions

View File

@@ -85,6 +85,15 @@ public sealed class TaskMergeService
await _broadcaster.WorktreeUpdated(taskId);
}
private async Task ApproveIfWaitingForReviewAsync(TaskEntity task, CancellationToken ct)
{
// A merged worktree means the work is integrated, so the task must reach Done.
// MarkWorktreeMergedAsync only flips the worktree state; transition the task
// itself when it was still awaiting review (a Done task is already terminal).
if (task.Status == TaskStatus.WaitingForReview)
await _state.ApproveReviewAsync(task.Id, ct);
}
public async Task<MergeResult> MergeAsync(
string taskId,
string targetBranch,
@@ -168,6 +177,7 @@ public sealed class TaskMergeService
}
await MarkWorktreeMergedAsync(taskId, ct);
await ApproveIfWaitingForReviewAsync(task, ct);
_logger.LogInformation(
"Merged task {TaskId} branch {Branch} into {Target} (remove worktree: {Remove})",
@@ -187,7 +197,7 @@ public sealed class TaskMergeService
public async Task<MergeResult> ContinueMergeAsync(string taskId, CancellationToken ct)
{
var (_, list, wt) = await LoadMergeContextAsync(taskId, ct);
var (task, list, wt) = await LoadMergeContextAsync(taskId, ct);
if (wt is null) return Blocked("task has no worktree");
if (wt.State != WorktreeState.Active) return Blocked($"worktree state is {wt.State}");
@@ -205,6 +215,7 @@ public sealed class TaskMergeService
catch (Exception ex) { return Blocked($"commit failed: {ex.Message}"); }
await MarkWorktreeMergedAsync(taskId, ct);
await ApproveIfWaitingForReviewAsync(task, ct);
_logger.LogInformation("Continued merge of task {TaskId} branch {Branch}", taskId, wt.BranchName);
return new MergeResult(StatusMerged, Array.Empty<string>(), null);
@@ -313,12 +324,8 @@ public sealed class TaskMergeService
? await _git.GetCurrentBranchAsync(list.WorkingDir, ct)
: targetBranch;
var merge = await MergeAsync(taskId, target, removeWorktree: false, $"Merge {wt.BranchName}", ct);
if (merge.Status != StatusMerged)
return merge;
var approve = await _state.ApproveReviewAsync(taskId, ct);
return approve.Ok ? merge : Blocked(approve.Reason ?? "approve failed");
// MergeAsync transitions the task WaitingForReview -> Done on a successful merge.
return await MergeAsync(taskId, target, removeWorktree: false, $"Merge {wt.BranchName}", ct);
}
private static MergeResult Blocked(string reason) =>