You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
=== formatZodError over a PLAIN strictObject rejection (control) ===
Transition (1 issue):
✗ (root): Unrecognized key(s) on this state transition: `guard`. … Did you mean `guard` → `cond`?
=== formatZodError over a UNION branch rejection ===
Action ref (1 issue):
✗ (root): Invalid input
第二例的处方并没有丢,它就在 payload 里:
issues[0].errors[1][0].message
= "Unrecognized key(s) on this action reference: `args`. Until #4001 …"
REST 层(packages/rest/src/rest-server.ts:610)把 error.issues 整体透传,所以 API 消费者拿得到;ZodError.message(JSON 序列化)也带着。只有压成单行的消费者会丢,而 formatZodError 的文档用途正是 CLI 输出(os validate / os compile)。
为什么值得单开
这是本战役第三类教训(「仪器谎报覆盖率」)的一个变体,而且方向更糟:不是闸门漏报,是拒绝信息本身在到达作者前被裁掉。战役自己的规矩是「拒绝信息里的散文是行为,不是文档」—— 对 union 后面的每一个 schema,这条在 CLI 路径上今天不成立。
受影响面不止 ActionRef / GuardRef:任何 union 成员是 strictObject 的地方都一样,ui/view.zod.ts 的 union 形状是最大的一处。随着 #4001 继续收紧,union 分支只会变多。
批 10 已就地钉住现状(packages/spec/src/automation/state-machine.test.ts 的 CONTROL — a non-union shape renders its full prescription through formatZodError),所以修好的那天这条钉会红,提醒把断言翻过来。
发现于 #4001 批 10(
automation/state-machine.zod.ts收紧),未在该 PR 中修复:改共享格式化器会改变全仓每一个 union 的 CLI 输出,不该搭在一个 spec 收紧 PR 上。现象
formatZodError(packages/spec/src/shared/error-map.zod.ts,从包根导出)只map顶层error.issues,从不下降进invalid_union的issue.errors[]。zod 对 union 只抛一个invalid_unionissue,其message是字面量"Invalid input",各分支的真实 issue 嵌在下一层。实测,同一个文件里的对照组(批 10 的测试里就钉着这一对):
第二例的处方并没有丢,它就在 payload 里:
REST 层(
packages/rest/src/rest-server.ts:610)把error.issues整体透传,所以 API 消费者拿得到;ZodError.message(JSON 序列化)也带着。只有压成单行的消费者会丢,而formatZodError的文档用途正是 CLI 输出(os validate/os compile)。为什么值得单开
这是本战役第三类教训(「仪器谎报覆盖率」)的一个变体,而且方向更糟:不是闸门漏报,是拒绝信息本身在到达作者前被裁掉。战役自己的规矩是「拒绝信息里的散文是行为,不是文档」—— 对 union 后面的每一个 schema,这条在 CLI 路径上今天不成立。
受影响面不止
ActionRef/GuardRef:任何 union 成员是strictObject的地方都一样,ui/view.zod.ts的 union 形状是最大的一处。随着 #4001 继续收紧,union 分支只会变多。处方(仅清点,未实施)
formatZodIssue对code === 'invalid_union'递归展开issue.errors,每个分支缩进一层;或只展开最有信息量的那个分支(unrecognized_keys 优于 invalid_type,避免把 "expected string" 的噪音也印出来)。需要一并考虑的:
formatZodError是公开导出(packages/spec/src/index.ts:128),输出变化对下游是可见行为变化 —— 大概率要 changeset。view曾经因为 union 遍历「一个未知键报两次」,见 未知键静默剥离仍是全仓默认:把 #3405 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) #4001 批 6c 的记录)。批 10 已就地钉住现状(
packages/spec/src/automation/state-machine.test.ts的CONTROL — a non-union shape renders its full prescription through formatZodError),所以修好的那天这条钉会红,提醒把断言翻过来。