From 560fdf128cca464a07049a8b3aa6c7ae6a980798 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 7 Aug 2026 13:12:59 +0000 Subject: [PATCH] =?UTF-8?q?fix(spec):=20fallbackNodeId=20=E5=A2=93?= =?UTF-8?q?=E7=A2=91=E6=8C=87=E5=90=91=E7=9C=9F=E6=AD=A3=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=20fault=20=E7=9A=84=E9=94=AE=20(#6094)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `flow.errorHandling.fallbackNodeId` 的退役迁移文案把 fault 边写成 「an edge with condition 'fault'」。但 `condition` 是返回 boolean 的 CEL 谓词(ExpressionInputSchema),fault 路由在 `type` (z.enum(['default','fault','conditional','back']))。 照原文案写 `{ source, target, condition: 'fault' }` 能 parse 通过 —— `condition` 接受任意表达式字符串 —— 但得到的是一条普通边,不是 fault 边。 于是墓碑用一个静默失效的键换掉了另一个:作者删掉一个本就不存在的 fallback, 再画一条并非 fault 的「fault 边」。 仓库别处已写对(flows.mdx:869「type: 'fault' is what routes — a label is not」),全树其余提法均为 `type: 'fault'`,此处是唯一一处走样。末句 「draw a fault edge from the failing node to the handler node instead」 本就正确,保持不变。 仅文案,无 schema / 校验 / 运行时行为变化。 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY --- .changeset/fault-edge-tombstone-type.md | 29 ++++++++++++++++++++++++ packages/spec/src/automation/flow.zod.ts | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .changeset/fault-edge-tombstone-type.md diff --git a/.changeset/fault-edge-tombstone-type.md b/.changeset/fault-edge-tombstone-type.md new file mode 100644 index 0000000000..787fb273a1 --- /dev/null +++ b/.changeset/fault-edge-tombstone-type.md @@ -0,0 +1,29 @@ +--- +"@objectstack/spec": patch +--- + +fix(spec): the `fallbackNodeId` tombstone names the key that actually routes faults (#6094) + +`flow.errorHandling.fallbackNodeId` was retired in 17.0.0 (#3896), and its +migration message tells the author what to draw instead. It named the wrong key: + +- FROM: "the engine routes unrecoverable node errors via per-node fault edges + (an edge with **condition `'fault'`**)" +- TO: "… (an edge with **`type: 'fault'`**)" + +`condition` on `FlowEdgeSchema` is a **CEL predicate** returning boolean +(`flow.zod.ts` — `ExpressionInputSchema`), while the fault/default/conditional/back +routing lives on `type` (`z.enum([...])`). An author following the old wording +verbatim would write `{ source, target, condition: 'fault' }`, which **parses +clean** — `condition` accepts any expression string — and produces an ordinary +edge that is not a fault path. So the tombstone handed them a second silently +inert key in exchange for the one it took away: they delete a fallback that never +existed, then draw a fault edge that isn't one. + +The repo already states the correct rule elsewhere (`flows.mdx`: "`type: 'fault'` +is what routes — a label is not"), and every other mention in the tree spells it +`type: 'fault'`; this was the only site out of step. The closing sentence +("draw a fault edge from the failing node to the handler node instead") was +already correct and is unchanged. + +Message text only — no schema, validation, or runtime behaviour changes. diff --git a/packages/spec/src/automation/flow.zod.ts b/packages/spec/src/automation/flow.zod.ts index f57b7f611e..94a6812452 100644 --- a/packages/spec/src/automation/flow.zod.ts +++ b/packages/spec/src/automation/flow.zod.ts @@ -712,7 +712,7 @@ export const FlowSchema = lazySchema(() => z.object({ fallbackNodeId: retiredKey( '`flow.errorHandling.fallbackNodeId` was removed in @objectstack/spec 17.0.0 (#3896 ' + 'audit close-out) — the engine routes unrecoverable node errors via per-node fault ' + - "edges (an edge with condition 'fault'), and never read this key: a fallback " + + "edges (an edge with type: 'fault'), and never read this key: a fallback " + 'configured here silently did not exist. Delete the key and draw a fault edge from ' + 'the failing node to the handler node instead.', ),