fix(metadata-protocol): getUiView 不再多发三个未声明键,响应体与 GetUiViewResponseSchema 对齐 (#5948) - #6271
Merged
Merged
Conversation
…hema 对齐 (#5948) GET /ui/view/:object/:type 由 getUiView 产出、REST 裸发(res.json,不套信封不校验)。 其声明是 GetUiViewResponseSchema(= ViewSchema),但实发 body 里的 list.object / form.object / form.label 三个键,ListViewSchema / FormViewSchema 这两个 strictObject 从未声明,实测 safeParse 判 unrecognized_keys 红。因为该 schema 全仓没有运行时读者, 这处分裂此前没有任何断言看得见。 - object 上移一层到容器(ViewSchema 一直在容器层声明它),成员层那份是冗余副本; - form.label(原 `Edit ${…}`)是渲染串而非元数据,直接摘除、不上移; - list.label 不动 —— ListViewSchema 正式声明了它。 packages/spec 零改动:本次是把实现修正到既有声明,而非改声明迁就实现。 常驻 pin 用生产端真实组装路径(实调 getUiView)喂 safeParse,而非手拼 fixture。 反向验证:恢复任一多发键 → pin 转红并点名该键。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
qq9340100
marked this pull request as ready for review
August 7, 2026 13:12
Collaborator
Author
|
ACCEPT(spec 车道 PM 验收, 逐 job 结论亲读:23 checks 全 completed,21 success + 2 预期 skipped(Console Pin Gate / Build Docs),ESLint 与 TypeScript Type Check 均
已翻 ready + 挂 auto-merge。#6239(五休眠声明退役)按维护者裁决排 #6083 之后,由本席巡检跟进。 Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5948
执行 2026-08-07 维护者重裁:选项 3(前提证伪后取代 03:19 的裁 A 字面落点)—— 生产端摘掉多发键,
packages/spec零改动,changesetpatch。一、前提修正(为什么落点和原单不同)
原单与裁 A 都称这条路由的 spec 声明是
GetViewResponseSchema—— 实测是张冠李戴,已在 issue 证据评论 逐条留档:getUiViewGetUiViewResponseSchema(protocol.zod.ts:363)=ViewSchema:1533protocol.ts:4179✅GET /ui/view/:object/:type✅getViewGetViewResponseSchema(:702)={object, view}:1560rest-server.ts:4895-4919调的是p.getUiView后res.json(view)。GetViewResponseSchema属于零实现零路由的 View-Management CRUD 块(已另立 #6239,维护者裁退役、排 #6083 后)。本 PR 不碰 spec,也不碰那五个休眠声明。真实缺陷在成员层:
ViewSchema容器本就声明list?/form?,但成员内多发的三个键被strictObject判红。二、判别键与真实形状(实测,非推测)
两条 return 的顶层键分别只有
list/form,无公共字面量判别键 —— 严格意义的z.discriminatedUnion在顶层不适用。这也是选项 3 更顺的原因之一:容器ViewSchema早已用「可选成员」表达了这个二选一,无需新建联合。改前实测(红色基线)
三、FROM → TO
「原来当 unknown 用的代码怎么改」:此前
client.meta.getView返回unknown,调用方要么不读、要么as any强读。改后 body 满足GetUiViewResponseSchema,即View:object的:body.list.object/body.form.object→body.object(相同的值上移一层,不是删除 ——ViewSchema一直在容器层声明object:「Object this container binds to」);body.form.label(原`Edit ${…}`)已摘除且不上移 —— 渲染串不属于元数据,任何 view schema 都没声明过它;调用方本就知道自己请求的对象,标题由 UI 自行拼;list.label的:不受影响,ListViewSchema正式声明了label,保持原样。消费面实测(定级 patch 的依据):
client-react的useView(metadata-hooks.tsx:229)把 body 当any透传(UseMetadataResult.data: any);objectui 全仓meta.getView零命中(其getView(objectName, viewId)走client.meta.getItem('view', …),另一条通路)。无编译期破坏面,无类型改判 ⇒patch。未验面:
cloud仓不在本次验证范围(按 #5540 口径如实标注)。若该仓直读body.list.object/body.form.object,按上面上移一层。四、常驻 pin 与反向验证
packages/metadata-protocol/src/protocol.ui-view-response-conformance.test.ts—— 刻意用生产端真实组装路径(实调getUiView)喂GetUiViewResponseSchema.safeParse,而不是手拼 fixture:手写 fixture 钉的是「本文件相信生产端发什么」,而那个相信恰恰就是此前错的东西。反向验证方向事先声明:本例是常规「红」向 —— pin 断言的是 full
safeParseGREEN 且 schema 为strictObject,故恢复任一多发键必然产出unrecognized_keys并点名。实跑结果与预测一致:恢复后 6/6 绿。key-vs-value 判据:本 pin 守的是键是否为该形状的合法成员,但断言取 full-parse-green 而非仅
unrecognized_keys缺席 —— 因为契约是「整个响应体满足声明」,只钉部分判据会放过其他漂移。五、验证
pnpm --filter @objectstack/metadata-protocol testpnpm --filter @objectstack/metadata-protocol build(含 DTS)dist/index.d.ts 197.37 KBcheck:route-envelopecheck:engine-double-contractcheck:type-check-coveragecheck:nul-bytes+ 改动文件自扫grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'无命中)check:empty-changeseteslint(改动文件,--no-inline-config)runtime/rest侧全部以vi.fn().mockResolvedValue(...)整体替身,钉的是 dispatcher 透传而非生产端形状 ⇒ 无 fixture 需迁移;domain-handler-registry+error-passthroughtargeted 跑 62 passed六、对在飞单的影响
packages/spec,GetUiViewResponse/GetUiViewResponseParsed别名对与同构 pin 均未触及。view的 spec 校验闸门形同虚设:saveMetaItem({ item: { nope: 1 } })返回 success 并把{"nope":1}存成一个 active view #5599(ui/view.zod.ts校验闸门):零文件相交(被否的选项 2 才会撞该文件,本 PR 未采纳)。options[]该不该讲字段级的逐选项词汇(color/visibleWhen)? —— 三处形状,三种拼法 #5016 /composeStacks的i18n仍是 last-wins —— #5005 裁决否掉的那个形状,只剩这一个键还在用 #5051 /functions: { fn: { handler, effect: 'writes' } }cannot surviveobjectstack build— lowering emits a shape FlowFunctionEntrySchema rejects #4976 / [spec]HookContext.api声明为z.unknown()—— 按(ctx: HookContext)标类型的 hook 无法调用ctx.api.object(…),而文档/技能全在这么教 #5945 / SDUI props 声明与 renderer 不一致:6 处「renderer 兑现但 ComponentPropsMap 未声明」+ 2 处「声明了没人读」(#5068 error 升级的 spec 侧前置) #5775 / ADR-0049 enforce-or-remove: ui/widget.zod.ts 全文件 + ui/i18n.zod.ts 五个形状实测无门(#4001 批 16 改判) #5055:零文件相交。Generated by Claude Code