FN-5772: re-anchor nested task worktree paths
Fix executor worktree invariant handling by re-anchoring nested task worktree paths to the actual git top-level. - add nested worktree root detection that only re-anchors when the top-level is a registered worktree inside the configured worktrees directory - update executor liveness gating and verifyWorktreeInvariants to persist re-anchored task.worktree values and retry checks safely - emit a new run-audit git mutation (worktree:reanchored) and add reliability tests/docs coverage plus a patch changeset Files changed: .changeset/fn-5772-worktree-reanchor.md | 7 +++ docs/architecture.md | 4 +- packages/engine/src/__tests__/reliability-interactions/executor-liveness-gate.test.ts | 33 ++++++++++ packages/engine/src/__tests__/verify-worktree-invariants-missing.test.ts | 62 +++++++++++++++++- packages/engine/src/__tests__/worktree-reanchor-nested-root.test.ts | 73 ++++++++++++++++++++++ packages/engine/src/executor.ts | 54 ++++++++++++++-- packages/engine/src/run-audit.ts | 1 + packages/engine/src/worktree-pool.ts | 63 +++++++++++++++++++ 8 files changed, 290 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-5772 Fusion-Task-Lineage: 475de161-7bc1-4359-bb76-20c4c07196d9
This commit is contained in:
@@ -103,6 +103,39 @@ describe("reliability interactions: FN-4935 executor liveness gate", () => {
|
||||
expect(events.some((event) => (event.type === "worktree:incomplete-detected" || event.mutationType === "worktree:incomplete-detected") && event.metadata?.source === "executor-liveness-gate" && event.metadata?.terminalAction === "requeue-todo")).toBe(true);
|
||||
});
|
||||
|
||||
it("re-anchors nested subdir classification failures instead of requeueing", async () => {
|
||||
vi.spyOn(worktreeAcquisition, "acquireTaskWorktree").mockResolvedValue({
|
||||
worktreePath: "/repo/.worktrees/gentle-flame/packages/core",
|
||||
branch: "fusion/fn-4935-t",
|
||||
source: "existing",
|
||||
hydrated: true,
|
||||
isResume: true,
|
||||
});
|
||||
vi.spyOn(worktreePool, "classifyTaskWorktree").mockResolvedValue({ ok: false, classification: "incomplete", reason: "missing .git metadata" });
|
||||
const reanchorSpy = vi.spyOn(worktreePool, "detectNestedWorktreeRoot").mockResolvedValue({ reanchored: true, root: "/repo/.worktrees/gentle-flame" });
|
||||
mockedExecSync.mockImplementation((cmd: string) => {
|
||||
if (cmd.includes("rev-parse HEAD")) return Buffer.from("abc123\n");
|
||||
if (cmd.includes("rev-parse --show-toplevel")) return Buffer.from("/repo/.worktrees/gentle-flame\n");
|
||||
if (cmd.includes("rev-parse --abbrev-ref HEAD")) return Buffer.from("fusion/fn-4935-t\n");
|
||||
if (cmd.includes("rev-list --count")) return Buffer.from("1\n");
|
||||
return Buffer.from("");
|
||||
});
|
||||
|
||||
const store = createMockStore();
|
||||
const executor = new TaskExecutor(store as any, "/repo");
|
||||
await executor.execute(makeTask());
|
||||
|
||||
expect(reanchorSpy).toHaveBeenCalled();
|
||||
expect(store.updateTask).toHaveBeenCalledWith("FN-4935-T", expect.objectContaining({ worktree: "/repo/.worktrees/gentle-flame" }));
|
||||
expect(store.logEntry).toHaveBeenCalledWith("FN-4935-T", expect.stringContaining("Re-anchored nested task.worktree"), undefined, expect.anything());
|
||||
expect(
|
||||
store.logEntry.mock.calls.some(
|
||||
(call: unknown[]) => call[0] === "FN-4935-T" && typeof call[1] === "string" && call[1].includes("not_usable_task_worktree"),
|
||||
),
|
||||
).toBe(false);
|
||||
expect(mockedCreateFnAgent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
"missing",
|
||||
"incomplete",
|
||||
|
||||
Reference in New Issue
Block a user