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。这一条是读路径:computeMetadataDiagnostics → decorateMetadataItem / decorateMetadataItems 给 getMetaItems() / 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.ts 的 z.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 目前只导出字符串渲染器,三个结构化消费者各抄一份),而不是继续按份数增长。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions