Skip to content

读路径 _diagnostics 是 union 折叠的第五个消费者:Studio 打开一个有缺陷的 view,内联字段错误同样只有一条 path:"" Invalid input #5598

Description

@os-zhuang

在做 #5364(saveMetaItem 的 422 展开 invalid_union,PR #5596)时核出的第五个消费者。#5364 的分诊帖把这条线数成"四份各自独立的消费端代码",实测是五份 —— 第五份就在 #5364 同一个包里,但在路径上,不在那单的文件面内,故独立记录。

落点

packages/metadata-protocol/src/metadata-diagnostics.ts:77(computeMetadataDiagnostics):

const parsed = (schema as z.ZodTypeAny).safeParse(candidate);
if (parsed.success) return { valid: true };

const errors = parsed.error.issues.map((issue) => ({
    path: issue.path.map(String).join('.'),
    message: issue.message,
    code: issue.code as string,
}));

#4971 / #5014 / #5341 / #5364 完全同一个 .map():只映射顶层 issue,issue.errors 里每个分支的真实拒绝理由(含 #4001 那批 strictObject 的策展处方)被丢弃。

为什么它是独立的一条

#5364 修的是 saveMetaItem路径 422。这一条是路径:computeMetadataDiagnosticsdecorateMetadataItem / decorateMetadataItemsgetMetaItems() / getMetaItem() 服务出去的每个文档挂 _diagnostics 信封,该文件自己的模块头写明用途是"so Studio (and any other consumer) can render validity badges, inline field errors, and governance dashboards"。

也就是说:#5364 修好之后,作者保存一个有缺陷的 view 能看到字段名了;但打开一个库里已经存着的有缺陷的 view,Studio 的内联字段错误仍然是一条没有字段的 Invalid input。两条路径的判决会不一致。

computeMetadataDiagnostics / decorateMetadataItem / decorateMetadataItems 都是 @objectstack/metadata-protocol 的公开导出(src/index.ts:29-32)。

实测(origin/main @ e900015)

#5364 那个同样的 view 输入:

computeMetadataDiagnostics('view', {
  name: 'task_list', object: 'task', type: 'list', label: 'Tasks',
  columns: [{ field: 'title', summary: { type: 'sum', fieldd: 'amount' } }],
})

得到:

{
 "valid": false,
 "errors": [
  { "path": "", "message": "Invalid input", "code": "invalid_union" }
 ]
}

ViewMetadataSchema 顶层本身是 union(view.zod.tsz.preprocess(stripViewConsoleDecorations, z.union([...]))),所以 view 类型的每一个有缺陷的存量文档都退化成这一条。

这一条的修法应当是最便宜的一次

PR #5596 已经在同一个包、同一个文件的隔壁落了 zodIssuesToMetadataIssues(issues),信封形态就是 { path, message, code }code 透传 zod 原码 —— 与 MetadataValidationResult.errors[] 的形态完全一致。所以这一条大概率是:导出/引入该函数,把上面那个 .map() 换掉,加读路径的回归测试。⚠️ 注意 computeMetadataDiagnostics 先做了 _diagnostics 的 strip(stripDiagnostics),那一段不要动。

判决必须与另外四处一致(丢弃只报根部 KIND 不匹配的分支;报得最少的分支胜出;unrecognized_keys 破平局;并列全出且有上限;嵌套 union 按绝对路径递归),否则同一个错误在保存时和打开时给出两套说法。

同族现状

# 消费者 文件 状态
1 formatZodError packages/spec/src/shared/error-map.zod.ts #4971(PR #5342)
2 zodIssuesToFields packages/rest/src/rest-server.ts #5014(PR #5362)
3 formatZodErrors packages/cli/src/utils/format.ts #5341 待派
4 saveMetaItem 的 422 packages/metadata-protocol/src/protocol.ts #5364(PR #5596 待评审)
5 computeMetadataDiagnostics packages/metadata-protocol/src/metadata-diagnostics.ts 本单

值得记一笔的是,这五个里有四个都是在修上一个的过程中发现的 —— 这类"同一机制多份拷贝"的缺陷靠一次静态扫描数不全。第 5 份修完后,或许值得单独裁决要不要把这套策略收敛成一个共享实现(spec 目前只导出字符串渲染器,三个结构化消费者各抄一份),而不是继续按份数增长。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions