fix(app-shell): judge a stored view by the wire gate, not the authoring gate - #3607
Merged
Merged
Conversation
…ring gate
metadata-admin's live client validation routed BOTH the create and the edit
draft through the AUTHORING schema (`ViewItemSchema` via `viewSchemaForDraft`).
Right for create, wrong for edit: the editor opens a body that came back out of
`sys_metadata`, and the platform itself writes keys into stored view bodies —
`isPinned` (view switcher pin), `sortOrder` (reorder), and a per-row `id` the
console filter/sort builders stamp on `config.filter[]`. `saveMetaItem` persists
the accepted body verbatim, so those keys are in storage by design.
Once the authoring gate was tightened, opening a pinned view reported
unrecognized keys — while the SERVER accepted the same body, validating it
against `ViewMetadataSchema`. The client was strictly stricter than the server.
`validateMetadataDraft` now takes `{ mode: 'create' | 'edit' }`. Create keeps the
authoring gate byte-identical; edit uses `ViewMetadataSchema`, the schema the
`view` metadata type registers and the server runs. `mode` defaults to 'create'
(the strict gate), so omitting it can only over-report, never widen the door.
`ViewMetadataSchema` rather than the narrower `ViewItemWireSchema`: the latter
covers only the ViewItem record and, measurably, still rejects
`config.filter[].id`, because that decoration is stripped by a `z.preprocess`
running ahead of every union member — reach a member-level `.strip()` lacks.
Not a try-both fallback: each mode has exactly one gate; a rejection is final.
Fixes objectstack-ai/objectstack#5316
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 objectstack-ai/objectstack#5316
问题
packages/app-shell/src/views/metadata-admin/clientValidation.ts的viewloader 把创建和编辑两条路都送进了授权门(ViewItemSchema,经viewSchemaForDraft)。创建路这样判是对的。编辑路不是 —— 编辑器打开的是一份从
sys_metadata取回的 body,而 stored view body 里带着平台自己写进去的键:isPinnedObjectView.tsx:882)sortOrderObjectView.tsx:931)config.filter[].idupdateView先 GET 存储项再 PUT{ ...current, ...partial },saveMetaItem校验后原样落库(ADR-0005 §Validation)—— 这些键在库里是设计如此,不是脏数据。objectstack#5074 把授权门收紧成真正的门之后(此前是 strip,这些键被静默丢弃),给某视图打过 pin 再进 metadata-admin 编辑器就会报未识别键 —— 而服务端接受同一份 body,因为它判的是
ViewMetadataSchema。客户端严于服务端,方向反了。修法
validateMetadataDraft增加可选第四参{ mode: 'create' | 'edit' }:ViewMetadataSchema——view元数据类型注册的那个 schema,也就是服务端saveMetaItem跑的同一个。客户端与服务端因此按构造同集,而不是靠人工维持相似。mode缺省为'create'(严的那个门)。漏传只会多报,绝不会静默把门放宽 —— 这是刻意选的缺省方向。唯一的生产调用点
ResourceEditPage.tsx传{ mode: createMode ? 'create' : 'edit' };createMode本就在该 effect 作用域内,没有新增状态,其余元数据类型的 loader 行为不变(签名多了个被忽略的参数)。SCHEMA_CACHE改为按mode:type作键 —— 否则view会把先到的那个 mode 的 schema 喂给另一个 mode。为什么是
ViewMetadataSchema而不是更窄的ViewItemWireSchema两者都在顶层声明了
isPinned/sortOrder,所以只看 issue 正文里那两个键分不出高下。实测把它们分开的是另外两条:ViewItemWireSchema只覆盖 ViewItem 记录,拒绝容器(编辑器确实会打开容器 —— 既有 pin 就钉着这条)。config.filter.0: unrecognized_keys误拒构建器写入的行id。那条 decoration 由ViewMetadataSchema的z.preprocess(stripViewConsoleDecorations, …)剥除,而 preprocess 跑在所有 union 成员之前,够得到成员级.strip()够不到的嵌套块 —— spec 在 union 定义处自己写明了这一点。也就是说:用
ViewItemWireSchema只能修掉一半的误拒,嵌套那一半照旧。不是 try-both 兜底
每个 mode 恰好一个门,拒绝即终局 —— 没有「换一个再试,过一个就算过」。
clientValidation.viewShapes.test.ts原有的后两条 pin 正是看守这个的,它们原样保留且全绿。验证
先复现,再修。把编辑路的期望写成 pin,在未改动的 main 上跑,预测红:
红的正是三条编辑路接受性 pin,报错内容与 issue 描述逐字吻合:
修后
12 passed (12)。反向验证(先定方向再跑):把
ViewMetadataSchema换成ViewItemWireSchema,预测恰好两条变红 —— 嵌套 decoration 那条和容器那条,而isPinned/sortOrder两条仍绿(wire 成员在顶层声明了它们)。实跑2 failed | 10 passed,与预测一致。这说明钉住 schema 选型的是嵌套与容器那两条 pin,顶层那两个键单独无法区分两个候选。全量:
packages/app-shell/src/views/metadata-admin共127 passed / 1169 tests;type-check干净;lint0 error;check-control-bytesOK。一条已测量的副作用(已单独立单,未在本 PR 处理)
ViewMetadataSchema是个 union,Zod 对 union 失败只给一条根级invalid_union,映射后成为path: ''/message: 'Invalid input'。判定仍然正确(坏 body 照样被拒,pin 有钉),但编辑路失去了逐字段内联定位和 spec 专门撰写的引导消息。这是修法的代价,不是 bug —— 更窄的候选已被上面两条实测排除,而消除它需要展开 union 的嵌套 errors 并解决「选哪个成员呈现」的取舍(启发式实测会误选),超出本单范围。已按发现纪律另开 #3606 交分诊定级。
影响面
仅 Studio 客户端预校验。服务端不受影响。变更集:
patch @object-ui/app-shell。Generated by Claude Code