FN-5818: fix shared-branch-group execution to use per-task working branches

Ensure shared branch-group flows consistently derive and acquire per-task working branches.

- update engine merge/executor/scheduler/self-healing paths to resolve task-scoped working branch names instead of shared branch-group names
- adjust worktree acquisition and already-merged detection logic to use the corrected branch resolution
- add regression coverage for shared-branch-group working-branch behavior, worktree acquisition, and worktree name derivation
- add a patch changeset for @runfusion/fusion

Files changed:
 .changeset/fn-5818-shared-branch-working-branch.md |  5 ++
 .../shared-branch-group-working-branch.test.ts     | 53 ++++++++++++++++++++++
 .../src/__tests__/worktree-acquisition.test.ts     | 52 +++++++++++++++++++++
 .../engine/src/__tests__/worktree-names.test.ts    | 20 +++++++-
 packages/engine/src/already-merged-detector.ts     |  6 +--
 packages/engine/src/executor.ts                    | 10 ++--
 packages/engine/src/merger-ai.ts                   |  4 +-
 packages/engine/src/merger.ts                      | 16 +++----
 packages/engine/src/scheduler.ts                   |  6 +--
 packages/engine/src/self-healing.ts                | 12 ++---
 packages/engine/src/worktree-acquisition.ts        |  4 +-
 packages/engine/src/worktree-names.ts              |  9 +++-
 12 files changed, 166 insertions(+), 31 deletions(-)

Fusion-Task-Id: FN-5818

Fusion-Task-Lineage: c7eb1ec4-971a-49ad-9156-5c0349c629aa
This commit is contained in:
gsxdsm
2026-06-01 01:37:25 -07:00
parent 6ade858235
commit 327f0a9a4f
12 changed files with 166 additions and 31 deletions

View File

@@ -0,0 +1,53 @@
import { describe, expect, it, vi } from "vitest";
import { acquireTaskWorktree } from "../../worktree-acquisition.js";
describe("shared branch group working branch regression", () => {
it("uses per-task working branches for shared members and keeps existing derivation modes", async () => {
const store = {
updateTask: vi.fn().mockResolvedValue(undefined),
logEntry: vi.fn().mockResolvedValue(undefined),
} as any;
const createWorktree = vi.fn(async (branchName: string, worktreePath: string) => ({ path: worktreePath, branch: branchName }));
const shared = { assignmentMode: "shared", groupId: "BG-1", source: "planning" } as const;
const [a, b] = await Promise.all([
acquireTaskWorktree({
task: { id: "FN-201", title: "a", description: "a", branch: "clionboarding", branchContext: shared, worktree: null } as any,
rootDir: process.cwd(),
store,
settings: {},
createWorktree,
}),
acquireTaskWorktree({
task: { id: "FN-202", title: "b", description: "b", branch: "clionboarding", branchContext: shared, worktree: null } as any,
rootDir: process.cwd(),
store,
settings: {},
createWorktree,
}),
]);
expect(a.branch).toBe("fusion/fn-201");
expect(b.branch).toBe("fusion/fn-202");
expect(a.branch).not.toBe(b.branch);
const perTask = await acquireTaskWorktree({
task: { id: "FN-203", title: "c", description: "c", branch: "fusion/custom", branchContext: { assignmentMode: "per-task-derived", groupId: "BG-1", source: "planning" }, worktree: null } as any,
rootDir: process.cwd(),
store,
settings: {},
createWorktree,
});
const ungrouped = await acquireTaskWorktree({
task: { id: "FN-204", title: "d", description: "d", branch: null, worktree: null } as any,
rootDir: process.cwd(),
store,
settings: {},
createWorktree,
});
expect(perTask.branch).toBe("fusion/custom");
expect(ungrouped.branch).toBe("fusion/fn-204");
});
});