FN-5767: wire workflow graph executor to legacy seams
Complete Phase 3 interpreter parity by routing workflow graph execution through legacy seam handlers. - Simplify workflow IR schema and built-in coding workflow to seam-based v1 nodes/edges. - Add workflow node handler layer with default legacy seam adapters and dedicated handler/parity tests. - Update engine exports/executor behavior for conditional traversal, retries, outcome context, and parity assertions. - Refresh core workflow IR tests/coverage for the new shape (including seam-stage expectations without triage) and remove obsolete schema fixture test. Files changed: .changeset/fn-5767-interpreter-parity.md | 5 + .github/actions/setup-node-pnpm/action.yml | 41 +--- docs/workflow-steps.md | 17 ++ .../__tests__/builtin-coding-workflow-ir.test.ts | 25 +-- packages/core/src/__tests__/workflow-ir.test.ts | 70 ------ packages/core/src/builtin-coding-workflow-ir.ts | 71 ++---- packages/core/src/index.ts | 31 +-- packages/core/src/workflow-ir-types.ts | 91 +------- packages/core/src/workflow-ir.ts | 246 ++------------------- .../workflow-graph-executor-handlers.test.ts | 201 +++++++++++++++++ .../workflow-graph-executor-parity.test.ts | 126 ++++++++--- .../src/__tests__/workflow-node-handlers.test.ts | 50 +++++ packages/engine/src/index.ts | 16 +- packages/engine/src/workflow-graph-executor.ts | 205 ++++++++++++----- packages/engine/src/workflow-node-handlers.ts | 56 +++++ 15 files changed, 661 insertions(+), 590 deletions(-) Fusion-Task-Id: FN-5767 Fusion-Task-Lineage: 0c68586e-2709-4521-a2ce-938ba1006ae0
This commit is contained in:
@@ -1,18 +1,12 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
BUILTIN_CODING_WORKFLOW_IR,
|
||||
WORKFLOW_IR_SCHEMA_VERSION,
|
||||
buildBuiltinCodingWorkflowIr,
|
||||
parseWorkflowIr,
|
||||
serializeWorkflowIr,
|
||||
} from "../index.js";
|
||||
import { BUILTIN_CODING_WORKFLOW_IR, parseWorkflowIr, serializeWorkflowIr } from "../index.js";
|
||||
|
||||
describe("builtin coding workflow ir", () => {
|
||||
it("parses and round-trips", () => {
|
||||
const parsed = parseWorkflowIr(BUILTIN_CODING_WORKFLOW_IR);
|
||||
const reparsed = parseWorkflowIr(serializeWorkflowIr(parsed));
|
||||
expect(reparsed).toEqual(parsed);
|
||||
expect(parsed.schemaVersion).toBe(WORKFLOW_IR_SCHEMA_VERSION);
|
||||
expect(parsed.version).toBe("v1");
|
||||
});
|
||||
|
||||
it("contains exactly one start and one end node", () => {
|
||||
@@ -21,14 +15,11 @@ describe("builtin coding workflow ir", () => {
|
||||
expect(nodes.filter((node) => node.kind === "end")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("exposes coding lifecycle stages", () => {
|
||||
const stageNodes = BUILTIN_CODING_WORKFLOW_IR.nodes.filter((node) => node.config?.stage);
|
||||
const stages = stageNodes.map((node) => String(node.config?.stage));
|
||||
expect(stages).toEqual(expect.arrayContaining(["triage", "execute", "review", "merge"]));
|
||||
});
|
||||
|
||||
it("builder returns parser-validated ir", () => {
|
||||
const built = buildBuiltinCodingWorkflowIr();
|
||||
expect(built.metadata.name).toContain("Coding Lifecycle");
|
||||
it("exposes coding lifecycle seams", () => {
|
||||
const seams = BUILTIN_CODING_WORKFLOW_IR.nodes
|
||||
.map((node) => String(node.config?.seam ?? ""))
|
||||
.filter((seam) => seam.length > 0);
|
||||
expect(seams).toEqual(expect.arrayContaining(["execute", "review", "merge"]));
|
||||
expect(seams).not.toContain("triage");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
BUILTIN_WORKFLOW_IR_FIXTURE,
|
||||
WORKFLOW_IR_SCHEMA_VERSION,
|
||||
parseWorkflowIr,
|
||||
serializeWorkflowIr,
|
||||
WorkflowIrError,
|
||||
} from "../index.js";
|
||||
|
||||
describe("workflow ir", () => {
|
||||
it("round-trips fixture with no data loss", () => {
|
||||
const serialized = serializeWorkflowIr(BUILTIN_WORKFLOW_IR_FIXTURE);
|
||||
const parsed = parseWorkflowIr(serialized);
|
||||
expect(parsed).toEqual(BUILTIN_WORKFLOW_IR_FIXTURE);
|
||||
});
|
||||
|
||||
it("rejects missing or mismatched schemaVersion", () => {
|
||||
expect(() =>
|
||||
parseWorkflowIr({
|
||||
metadata: { name: "missing-version" },
|
||||
nodes: [],
|
||||
edges: [],
|
||||
}),
|
||||
).toThrowError(expect.objectContaining({ code: "unsupported_version" }));
|
||||
|
||||
expect(() =>
|
||||
parseWorkflowIr({
|
||||
schemaVersion: "2.0.0",
|
||||
metadata: { name: "wrong-version" },
|
||||
nodes: [],
|
||||
edges: [],
|
||||
}),
|
||||
).toThrowError(expect.objectContaining({ code: "unsupported_version" }));
|
||||
});
|
||||
|
||||
it("rejects unknown node kinds and dangling edges", () => {
|
||||
expect(() =>
|
||||
parseWorkflowIr({
|
||||
schemaVersion: WORKFLOW_IR_SCHEMA_VERSION,
|
||||
metadata: { name: "unknown-kind" },
|
||||
nodes: [{ id: "n1", kind: "custom" }],
|
||||
edges: [],
|
||||
}),
|
||||
).toThrowError(WorkflowIrError);
|
||||
|
||||
expect(() =>
|
||||
parseWorkflowIr({
|
||||
schemaVersion: WORKFLOW_IR_SCHEMA_VERSION,
|
||||
metadata: { name: "dangling-edge" },
|
||||
nodes: [{ id: "start", kind: "start" }],
|
||||
edges: [{ id: "e1", from: "start", to: "missing" }],
|
||||
}),
|
||||
).toThrowError(expect.objectContaining({ code: "dangling_edge" }));
|
||||
});
|
||||
|
||||
it("parses fixture JSON string for interpreter parity", () => {
|
||||
const json = JSON.stringify(BUILTIN_WORKFLOW_IR_FIXTURE);
|
||||
const parsed = parseWorkflowIr(json);
|
||||
|
||||
expect(parsed.schemaVersion).toBe(WORKFLOW_IR_SCHEMA_VERSION);
|
||||
expect(parsed.nodes.length).toBeGreaterThanOrEqual(1);
|
||||
expect(parsed.edges.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it("exposes workflow ir surface from package entry", () => {
|
||||
expect(typeof parseWorkflowIr).toBe("function");
|
||||
expect(typeof serializeWorkflowIr).toBe("function");
|
||||
expect(BUILTIN_WORKFLOW_IR_FIXTURE.schemaVersion).toBe(WORKFLOW_IR_SCHEMA_VERSION);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user