feat(worker): fast-forward finished children into the parent's unit branch

Planning parents get their own worktree on Queue plan, children fork from the
unit head and are absorbed via merge --ff-only before Done (ff failure -> Failed,
interactive child approve -> absorb instead of merge to the target).
This commit is contained in:
mika kuns
2026-10-01 11:25:47 +02:00
parent 724ad90f88
commit 9da522b0c9
8 changed files with 489 additions and 17 deletions
@@ -1,5 +1,6 @@
using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Worker.Runner;
using ClaudeDo.Worker.State;
using Microsoft.EntityFrameworkCore;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
@@ -10,13 +11,16 @@ public sealed class PlanningChainCoordinator
{
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
private readonly Func<ITaskStateService> _state;
private readonly UnitBranchService? _unitBranch;
public PlanningChainCoordinator(
IDbContextFactory<ClaudeDoDbContext> dbFactory,
Func<ITaskStateService> state)
Func<ITaskStateService> state,
UnitBranchService? unitBranch = null)
{
_dbFactory = dbFactory;
_state = state;
_unitBranch = unitBranch;
}
// Sets up a sequential chain over a planning parent's children.
@@ -86,6 +90,9 @@ public sealed class PlanningChainCoordinator
if (phase != PlanningPhase.Finalized)
throw new InvalidOperationException("Plan must be finalized before it can be queued.");
// The parent's worktree is the unit branch every child forks from and is absorbed into.
if (_unitBranch is not null)
await _unitBranch.EnsureUnitWorktreeAsync(parentTaskId, ct);
return await SetupChainAsync(parentTaskId, enqueue: true, ct);
}