FN-6035: align builtin coding workflow registry with canonical IR

Keep builtin:coding anchored to the canonical coding workflow IR across registry, resolver, and docs.

- add regression coverage that builtin:coding reuses BUILTIN_CODING_WORKFLOW_IR and preserves canonical columns, traits, settings, and enabled ordering
- extend workflow IR resolver/settings tests to pin canonical builtin fallback behavior for explicit and missing built-in selections
- document builtin:coding as the canonical default/fallback workflow and add a patch changeset for @runfusion/fusion

Files changed:
 .../FN-6035-builtin-coding-workflow-parity.md      |  5 ++
 docs/workflow-steps.md                             |  4 +-
 .../core/src/__tests__/builtin-workflows.test.ts   | 65 +++++++++++++++++++++-
 .../src/__tests__/workflow-ir-resolver.test.ts     | 18 +++++-
 .../src/__tests__/workflow-ir-settings.test.ts     |  3 +
 5 files changed, 92 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-6035

Fusion-Task-Lineage: ece0c8c6-810f-44b1-afb3-6545d3156459
This commit is contained in:
gsxdsm
2026-06-08 12:52:32 -07:00
parent c8cb740b93
commit 9c84ba2e9f
5 changed files with 92 additions and 3 deletions

View File

@@ -1,7 +1,13 @@
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { BUILTIN_WORKFLOWS, getBuiltinWorkflow, isBuiltinWorkflowId } from "../builtin-workflows.js";
import {
BUILTIN_WORKFLOWS,
defaultEnabledBuiltinWorkflowIds,
getBuiltinWorkflow,
isBuiltinWorkflowId,
} from "../builtin-workflows.js";
import { BUILTIN_CODING_WORKFLOW_IR } from "../builtin-coding-workflow-ir.js";
import { BUILTIN_WORKFLOW_SETTINGS } from "../builtin-workflow-settings.js";
import { resolveColumnFlags } from "../trait-registry.js";
import { compileWorkflowToSteps } from "../workflow-compiler.js";
import { DEFAULT_WORKFLOW_COLUMN_IDS, parseWorkflowIr, serializeWorkflowIr } from "../workflow-ir.js";
@@ -89,6 +95,63 @@ describe("built-in workflows", () => {
]);
});
it("builtin:coding catalog entry is backed by the canonical coding IR", () => {
const coding = getBuiltinWorkflow("builtin:coding");
expect(coding).toBeDefined();
expect(coding!.id).toBe("builtin:coding");
expect(coding!.name).toBe("Coding (built-in)");
expect(coding!.description).toContain("standard coding pipeline");
expect(coding!.kind).toBe("workflow");
expect(coding!.createdAt).toBe("2026-01-01T00:00:00.000Z");
expect(coding!.updatedAt).toBe("2026-01-01T00:00:00.000Z");
expect(coding!.ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(serializeWorkflowIr(coding!.ir)).toBe(serializeWorkflowIr(BUILTIN_CODING_WORKFLOW_IR));
});
it("builtin:coding catalog IR exposes canonical columns, placements, and settings", () => {
const coding = getBuiltinWorkflow("builtin:coding")!;
const ir = parseWorkflowIr(coding.ir);
expect(ir.version).toBe("v2");
if (ir.version !== "v2") throw new Error("expected v2");
expect(ir.columns.map((column) => column.id)).toEqual([
"triage",
"todo",
"in-progress",
"in-review",
"done",
"archived",
]);
expect(ir.columns.map((column) => column.traits.map((trait) => trait.trait))).toEqual([
["intake"],
["hold", "reset-on-entry"],
["wip", "abort-on-exit", "timing"],
["merge-blocker", "human-review", "stall-detection", "merge"],
["complete"],
["archived"],
]);
const byId = new Map(ir.nodes.map((node) => [node.id, node]));
expect(byId.get("execute")?.column).toBe("in-progress");
expect(byId.get("review")?.column).toBe("in-review");
expect(byId.get("merge")?.column).toBe("in-review");
expect(ir.settings).toEqual(BUILTIN_WORKFLOW_SETTINGS);
});
it("repeated catalog reads and listings keep builtin:coding in the enabled order", () => {
expect(getBuiltinWorkflow("builtin:coding")?.ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(getBuiltinWorkflow("builtin:coding")?.ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(BUILTIN_WORKFLOWS.find((workflow) => workflow.id === "builtin:coding")?.ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(defaultEnabledBuiltinWorkflowIds()).toEqual(BUILTIN_WORKFLOWS.map((workflow) => workflow.id));
expect(defaultEnabledBuiltinWorkflowIds().slice(0, 5)).toEqual([
"builtin:coding",
"builtin:quick-fix",
"builtin:review-heavy",
"builtin:compound-engineering",
"builtin:stepwise-coding",
]);
});
it("builtin:coding exposes execute retries after registry lookup and parse round-trip", () => {
const coding = getBuiltinWorkflow("builtin:coding");
expect(coding).toBeDefined();

View File

@@ -89,10 +89,12 @@ describe("resolveWorkflowIrForTask", () => {
});
describe("resolveWorkflowIrById", () => {
it("resolves builtin:coding to the authored v2 IR with review column traits", async () => {
it("resolves builtin:coding to the canonical authored v2 IR with review column traits", async () => {
const store = makeStore({});
const ir = await resolveWorkflowIrById(store, "builtin:coding");
expect(ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(ir).toBe(getBuiltinWorkflow("builtin:coding")!.ir);
expect(ir.version).toBe("v2");
if (ir.version !== "v2") throw new Error("expected v2");
const inReview = ir.columns.find((column) => column.id === "in-review");
@@ -103,6 +105,20 @@ describe("resolveWorkflowIrById", () => {
);
});
it("resolves an explicit builtin:coding task selection through the canonical IR path", async () => {
const store = makeStore({ selection: { workflowId: "builtin:coding", stepIds: [] } });
const ir = await resolveWorkflowIrForTask(store, "t1");
expect(ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(store.getWorkflowDefinition).not.toHaveBeenCalled();
});
it("falls back to the canonical IR for an unknown built-in id", async () => {
const store = makeStore({});
const ir = await resolveWorkflowIrById(store, "builtin:missing");
expect(ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect(store.getWorkflowDefinition).not.toHaveBeenCalled();
});
it("parses a raw-string IR from the definition", async () => {
const raw = JSON.stringify(CUSTOM_IR);
const store = makeStore({ defs: { "wf-raw": { ir: raw } } });

View File

@@ -6,6 +6,7 @@ import {
WorkflowIrError,
} from "../workflow-ir.js";
import { BUILTIN_CODING_WORKFLOW_IR } from "../builtin-coding-workflow-ir.js";
import { getBuiltinWorkflow } from "../builtin-workflows.js";
import { BUILTIN_WORKFLOW_SETTINGS } from "../builtin-workflow-settings.js";
import { DEFAULT_PROJECT_SETTINGS } from "../types.js";
import type {
@@ -214,6 +215,8 @@ describe("built-in workflow settings parity anchor (U1, R4)", () => {
expect(declaredIds.has(setting.id)).toBe(true);
}
expect(builtin.settings).toEqual(BUILTIN_WORKFLOW_SETTINGS);
expect(getBuiltinWorkflow("builtin:coding")!.ir).toBe(BUILTIN_CODING_WORKFLOW_IR);
expect((getBuiltinWorkflow("builtin:coding")!.ir as WorkflowIrV2).settings).toEqual(BUILTIN_WORKFLOW_SETTINGS);
});
it("the moved-key catalog has left DEFAULT_PROJECT_SETTINGS (U4 hard-move) and pins its legacy defaults", () => {