Repository navigation
script 的 config 契约要接入 #4277 的执行期 parse,先得有判别式(actionType)形态 #4343
Copy link
Copy link
Closed
Labels
Description
Activity
方向变更(操作者裁定):不再给
script的多形态做判别式契约,改为激进收敛——script收敛为纯函数调用节点(function必需 +inputs+outputVariable),actionType/template/recipients/variables/script五键按 ADR-0049 removal 路线打retiredKey()墓碑(处方:email →notify;slack →connector_action/http;内联脚本与函数名简写 → 注册函数),并注册 ADR-0087 D2 conversion。理由:四个分支里只有函数路径跑真实逻辑(email/slack 是 logger stub、内联 script 是 no-op、其余 actionType 是函数名别名),多形态是历史积累。收敛后契约天然平铺,
script/subflow直接接入 #4277 的执行期 parse——本 issue 的目标以更简单的形态达成;墓碑处方也正是经这条 parse 通道对存量 JSON 元数据发声(load 路径不 parse config)。decision维持现状。本 session 接手实施,分支
claude/script-config-parse-contract-gy035e(objectstack + objectui 配套),PR 链接随后附上。
Generated by Claude Code
PR 已开(均为 draft):
- framework:feat(spec,automation)!: converge
scriptto a function call and parse script/subflow config at execute time (#4343) #4516 —— 5 个键retiredKey()墓碑 +flow-node-script-branch-keys-removedD2 conversion(step 17 接线,retiredFromLoadPath)+script/subflow接入parseNodeConfig()+ 例子/skills/docs 清理 - objectui:feat(flow-designer)!: the script node authors a function call, and nothing else (framework#4343) objectui#3170 —— 表单收敛为函数路径,五个退役键降级为 legacy 只读渲染;跨仓对账测试按 spec 新旧双态断言,
SCRIPT_BUILTIN_ACTION_TYPES是否存在作为判别依据
两点执行中发现、与原计划不同的事实,记在这里:
- 墓碑对存量 JSON 元数据是听不见的,靠执行期 parse 也不是。load 路径从不 parse 节点 config(
FlowNodeSchema.config是z.record(z.unknown())),而registerFlow会连退役 conversion 一起重放([P2] The spec contract stops at authored source — stored metadata is rehydrated unparsed, unconverted, and ungated #3903——sys_metadata里的行没有作者可教)。所以存量流程走的是「注册时被 conversion 剥掉没人读的键 → 执行期因为没有 callable 被拒」,墓碑本身只对写 TypeScript 的作者和直接 parse 的调用者发声。真正的行为翻转是老的 email-stub 节点从「打一行日志报成功」变成「大声拒绝」。 flow-node-script-config-aliases([P3] Six flow-node config aliases bypassreadAliasedConfig— no warning, no ledger, no retirement path #3796)的 fixture 两侧都带actionType: 'invoke_function',那个终态在 17 已不可达,fixture 已改写(conversion 本体未动)——与wait声明了超时契约但完全没有实现:onTimeout零读取者,timeoutMs被当成定时时长用 —— showcase 自己在依赖它 #4158 退役时踩到的是同一类交互。
decision按 issue 建议维持现状。
Generated by Claude Code
- framework:feat(spec,automation)!: converge
- added a commit that references this issue
on Aug 1, 2026 - added a commit that references this issue
on Aug 3, 2026 - added a commit that references this issue
on Sep 1, 2026 - added a commit that references this issue
on Sep 29, 2026 - added 3 commits that reference this issue
on Oct 7, 2026
#4278 与 #4277 在同一天落地,两者交界处留下一个明确的后续,记在这里以免被当成「忘了接」。
现状
#4277(#4332)让 12 个「有契约」的内置节点在执行前
parse()自己的node.config(service-automation/builtin/parse-config.ts),并让registerFlow()拒绝 descriptor
configSchema未声明的键。#4278(#4325)给另外三个 descriptor-schemaless 节点补上了执行器派生的契约
(
spec/automation/schemaless-node-config.zod.ts:ScriptConfigSchema/SubflowConfigSchema/DecisionConfigSchema),但刻意没有接入 parse,也没有发布descriptor
configSchema——两件事是同一个理由。为什么不能直接接上去
它们的键集不等于契约。
script—— 合法键随actionType变:内置副作用分支读template/recipients/variables;函数分支读function/inputs/outputVariable;内联script是被识别但不执行的第三种。平铺 parse 只能取这些键的并集,于是
{ actionType: 'email', function: 'x' }这种自相矛盾的配置照样通过——检了个寂寞;若反过来收紧成任一分支,就会拒绝另一半合法元数据。
decision—— 完全可以不带conditions,只靠出边的edge.condition分支(这是遗留但合法的形态)。
subflow—— 这个其实最接近可接入:键集扁平,flowName执行期必需,执行器已经用
refuseNode()拒绝缺失的情况。建议做法
subflow可以先接——低风险,把现有的refuseNode换成统一的 parse guard,与其它 12 个节点的失败形态一致(guard refusal,不走 fault 边)。
script需要先改造成判别式:按actionType拆成z.discriminatedUnion(或等价的superRefine),分支分别声明各自的键。这同时会让「自相矛盾的配置」在作者时就被拒,而不是运行到一半才发现
——
actionType: 'email'却写了function是当前唯一还能悄悄通过的形态。decision大概率维持现状:它的真实契约一半在边上,不在 config 里;接 parse 的收益仅限于「
conditions[]元素的类型」,可以等 2 做完再评估。一个附带好处:
script一旦有了判别式形态,objectui 的flow-node-config.spec-reconciliation.test.ts(objectui#3099)可以从「键集并集比对」升级为「按
actionType分支比对表单的showWhen分组」——那才是表单实际的形状,也能挡住「某个分支少提供了一个字段」这类 #4278 没覆盖到的漂移。
Related
scriptoffers three broken options and cannot author the one that works #4278 —— schemaless 节点的表单无人对账(已关闭)parse()their config, and tighten the undeclared-key warning into an error #4277 / feat(automation,spec): 流程执行器 parse() 自己的 config,未声明键在注册时报错 (#4277) #4332 —— 执行器 parse config + registerFlow 拒绝未声明键config.function作为 canonical 调用引用的来源