From e67932c83c3235feda220f74ef98ce5468d61e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 07:38:14 +0000 Subject: [PATCH] fix: accept omitted condition in fallback transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fallback transitions (last entry in graph node) omit the condition field in YAML, resulting in undefined instead of null. The validator and materializer now handle this: - validate.ts: accept undefined as valid condition value - workflow.ts: normalizeGraph() coerces undefined → null before CAS put This was broken by the graph fallback pattern introduced in #370. --- .../cli-workflow/src/commands/workflow.ts | 21 +++++++++++++++++-- packages/cli-workflow/src/validate.ts | 5 ++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/cli-workflow/src/commands/workflow.ts b/packages/cli-workflow/src/commands/workflow.ts index 8bc1f84..782f2b5 100644 --- a/packages/cli-workflow/src/commands/workflow.ts +++ b/packages/cli-workflow/src/commands/workflow.ts @@ -2,7 +2,12 @@ import { readFile } from "node:fs/promises"; import type { JSONSchema } from "@uncaged/json-cas"; import { putSchema, validate } from "@uncaged/json-cas"; -import type { CasRef, RoleDefinition, WorkflowPayload } from "@uncaged/workflow-protocol"; +import type { + CasRef, + RoleDefinition, + Transition, + WorkflowPayload, +} from "@uncaged/workflow-protocol"; import { parse } from "yaml"; import { @@ -46,6 +51,18 @@ function isJsonSchema(value: unknown): value is JSONSchema { return typeof value === "object" && value !== null && !Array.isArray(value); } +/** Normalize graph transitions: ensure condition is null (not undefined) for fallback entries. */ +function normalizeGraph(graph: Record): Record { + const result: Record = {}; + for (const [node, transitions] of Object.entries(graph)) { + result[node] = transitions.map((t) => ({ + role: t.role, + condition: t.condition ?? null, + })); + } + return result; +} + async function resolveFrontmatterRef( uwf: UwfStore, roleName: string, @@ -84,7 +101,7 @@ export async function materializeWorkflowPayload( description: raw.description, roles, conditions: raw.conditions, - graph: raw.graph, + graph: normalizeGraph(raw.graph), }; } diff --git a/packages/cli-workflow/src/validate.ts b/packages/cli-workflow/src/validate.ts index 5a3a5cc..6cffdef 100644 --- a/packages/cli-workflow/src/validate.ts +++ b/packages/cli-workflow/src/validate.ts @@ -42,7 +42,10 @@ function isTransition(value: unknown): boolean { return false; } const condition = value.condition; - return typeof value.role === "string" && (condition === null || typeof condition === "string"); + return ( + typeof value.role === "string" && + (condition === null || condition === undefined || typeof condition === "string") + ); } function isStringRecord(value: unknown, itemCheck: (item: unknown) => boolean): boolean { -- 2.43.0