Skip to content

fix(metadata-protocol): 读路径 _diagnostics 保留 union 分支的真实拒绝理由 (#5598) - #5765

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5598-diagnostics-union-branches
Aug 6, 2026
Merged

fix(metadata-protocol): 读路径 _diagnostics 保留 union 分支的真实拒绝理由 (#5598)#5765
os-zhuang merged 1 commit into
mainfrom
claude/issue-5598-diagnostics-union-branches

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5598

问题

computeMetadataDiagnostics(packages/metadata-protocol/src/metadata-diagnostics.ts)把 zod 的 error.issues 直接 .map()_diagnostics 信封条目。zod 会把一个失败 z.union全部分支折叠成一条顶层 issue —— path 为空串、message 是字面量 "Invalid input" —— 而 ViewMetadataSchema 顶层本身就是 union(z.preprocess(stripViewConsoleDecorations, z.union([...]))),所以库里每一个有缺陷的 view 文档读出来都退化成这一条没有字段名的记录。该文件模块头承诺的用途正是让 Studio 渲染 validity badge、内联字段错误和治理看板,而内联字段错误无处可标。

这不只是"少了点信息",而是同一份文档在两条路径上判决不一致:#5364(PR #5596)修好写路径之后,作者保存一个有缺陷的 view 能看到出错的键名;打开同一份已存在库里的文档却仍然只得到一条 Invalid input。这是同一机制的第 5 个消费者(#4971 / #5014 / #5341 / #5364 是前四个)。

改动

metadata-diagnostics.ts 一处 .map() 换成调用同包 #5596 已落地并导出的 zodIssuesToMetadataIssues复用而非再抄一份策略是重点:分支选取口径(丢弃只报根部 KIND 不匹配的分支;报得最少的分支胜出;unrecognized_keys 破平局;并列全出且有上限;嵌套 union 按绝对路径递归)由该函数单点定义,读写两路径按构造一致,不可能各自漂移。

  • ⛔ 未改 protocol.ts —— 该函数已是模块级 export,无需移动或调整导出。
  • stripDiagnostics 一段未动;新增用例专门守住"读两遍不会把信封自己判成非法"。
  • 对消费者是纯增量:union 自己那条记录仍排在 errors[0],后面才跟上解释它的分支条目,读 errors[0] 的既有代码读到的还是同一条。

实测,issue 正文那份 view 输入现在得到:

{ "valid": false, "errors": [
  { "path": "", "message": "Invalid input", "code": "invalid_union" },
  { "path": "", "code": "unrecognized_keys",
    "message": "Unrecognized key(s) on this view container: `type`, `columns`. …
      • `type` belongs to a single VIEW, not to the container. Wrap it: …" }
] }

第二条正是 #4001 那批 strictObject 的策展处方 —— 以前被 .map() 生产出来又丢掉。

测试

新增 packages/metadata-protocol/src/metadata-diagnostics.union-issues.test.ts(8 例):3 例守 union 展开(展开发生、与共享排序逐字节一致、decorateMetadataItem 把它带到 Studio 面前),1 例守 strip 未被破坏,4 例是对照组 —— 没走 union 的普通字段级拒绝、非对象文档、spec 合法文档、未注册类型,行为必须不变。

反向验证(方向事先预判:红):把删掉的 .map() 限肢放回去,3 条 union 用例转红、4 条对照组保持绿 —— 缺陷本身被写成了一个数字:

 × expands the union instead of serving one rootless "Invalid input"
 × serves the same verdict the save path serves — one ranking, not two
 × reaches the Studio-facing surface — `decorateMetadataItem` carries it
AssertionError: expected 1 to be greater than 1
 Test Files  1 failed (1)      Tests  3 failed | 5 passed (8)

恢复修复后:

packages/metadata-protocol  vitest run
 Test Files  46 passed (46)      Tests  427 passed (427)

消费半径清扫(该判决在哪里被读就在哪里查 fixture,不按被改包划界):git grep _diagnostics 覆盖 metadata-protocol / objectql / metadata / rest / service-automation —— 除 objectql 外均只断言 valid 标志或 warning(另一个生产者),不受增量影响;objectql 直接测 computeMetadataDiagnostics,已跑:

packages/objectql  vitest run src/metadata-diagnostics.test.ts src/protocol-meta.test.ts
 Test Files  2 passed (2)      Tests  92 passed (92)

typecheck / 构建 / 门禁:

  • tsc --noEmit -p packages/metadata-protocol/tsconfig.json —— 改动前后输出逐行相同(159 行,全是该包既有的 test-layer DEBT,check:type-check-coverage 已登记),我的两个文件零错误。
  • pnpm --filter @objectstack/metadata-protocol build —— tsup ESM/CJS/DTS 全部 Build success,无循环依赖告警。
  • check:nul-bytes OK(5641 文件)、check:type-check-coverage OK、check:query-options-erasure OK(baseline 对 5e3c83b 核过,无新增文件)、check:slot-lookup OK、check:published-files OK、check:error-code-casing OK;两个文件 eslint --no-inline-config 干净。

需要评审注意的一点

metadata-diagnostics.ts 现在 import { zodIssuesToMetadataIssues } from './protocol.js',而 protocol.ts 本来就 import 了 metadata-diagnostics.js,于是两个模块间形成一个包内循环 import。运行期安全(函数声明提升,zodIssuesToMetadataIssues 只在运行期被调用,两个模块都没有模块级互相调用),tsup 打包与 DTS 均无告警,全量测试绿。但方向上是小叶子模块反向依赖了大模块 —— 这正好给 issue 正文那条后续裁决项(「五处策略是否收敛成一个共享实现」)多加一个论据:真正的落点应该是一个中立模块,而不是继续按份数增长。按派单约束我没有动 protocol.ts,这条留给 PM 裁决。


Generated by Claude Code

computeMetadataDiagnostics 把 zod 的 error.issues 直接 .map() 成 _diagnostics
条目。zod 会把一个失败 z.union 的全部分支折叠成一条顶层 issue —— path 为空、
message 是字面量 "Invalid input" —— 而 ViewMetadataSchema 顶层本身就是 union,
所以库里每一个有缺陷的 view 读出来都退化成这一条没有字段名的记录,模块头承诺的
"内联字段错误"无处可标。

后果是同一份文档在两条路径上判决不一致:#5364(PR #5596)修好写路径之后,保存
一个有缺陷的 view 能看到出错的键名,打开同一份已存库的文档却仍然只有一条
Invalid input。

改法是复用而非再抄一份策略:读路径改调同包 #5596 落地的
zodIssuesToMetadataIssues,分支选取口径由该函数单点定义,读写两路径按构造一致。
展开是纯增量 —— union 自己那条仍在 errors[0]。stripDiagnostics 一段未动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V7WetGmnfoXNn8cLieKKmx
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 4:17am

Request Review

@github-actions github-actions Bot added the size/m label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/metadata-protocol)
  • content/docs/releases/v9.mdx (via @objectstack/metadata-protocol)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 6, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 6, 2026 05:14
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit dde9202 Aug 6, 2026
24 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5598-diagnostics-union-branches branch August 6, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants