feat(FN-5438): add manual merge blocker bypass mode for queued tasks

Adds a manual merge blocker mode (FN-5438) that prevents automatic merging and provides a bypass mechanism to resume, wired through the merger, project engine, and task workflow API routes. Includes tests across core, engine route registration, and project engine layers, plus a changeset and documen

Fusion-Task-Id: FN-5438
This commit is contained in:
Fusion (runfusion.ai)
2026-05-21 18:28:07 -07:00
committed by gsxdsm
parent 854045f430
commit 025683ca60
10 changed files with 195 additions and 6 deletions

View File

@@ -0,0 +1,34 @@
// @vitest-environment node
import { describe, expect, it, vi } from "vitest";
import express from "express";
import type { TaskStore } from "@fusion/core";
import { createApiRoutes } from "../../routes.js";
import { request as REQUEST } from "../../test-request.js";
describe("task workflow merge route", () => {
it("invokes engine.onMerge for manual merge requests", async () => {
const store: TaskStore = {
getRootDir: vi.fn(() => process.cwd()),
mergeTask: vi.fn(),
} as unknown as TaskStore;
const onMerge = vi.fn(async (id: string) => ({
task: { id, column: "done" },
branch: `fusion/${id.toLowerCase()}`,
merged: true,
worktreeRemoved: false,
branchDeleted: false,
}));
const app = express();
app.use(express.json());
app.use("/api", createApiRoutes(store, { onMerge }));
const res = await REQUEST(app, "POST", "/api/tasks/FN-5438/merge");
expect(res.status).toBe(200);
expect(onMerge).toHaveBeenCalledWith("FN-5438");
expect((res.body as { merged: boolean }).merged).toBe(true);
});
});

View File

@@ -997,7 +997,10 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
try {
const { store: scopedStore, engine } = await getProjectContext(req);
const merge = engine
? (id: string) => engine.onMerge(id)
? (id: string) => {
// Manual merge: bypasses scheduler-transient status blockers (FN-5438). Hard guards still apply.
return engine.onMerge(id);
}
: options?.onMerge ?? ((id: string) => scopedStore.mergeTask(id));
const result = await merge(req.params.id);
res.json(result);