feat(spec)!: view 面收紧 —— #4001 最后一批 - #4534
Merged
Merged
Conversation
Views are the surface an author iterates on visually, which is why a dropped key
hides here: the view still renders, just not the way it was described.
`FormFieldBase` / `FormSection` / `FormButtonConfig` closed years ago under
ADR-0089 D3a; the other forty-odd shapes kept the posture those three were
rescued from.
`defineView`'s guard was another one-door workaround — its own comment says
"`ViewSchema` strips unknown top-level keys, so a flat list view would parse to
an empty container". Fifth bespoke guard this campaign has found built around
silent stripping, and like all of them it covered exactly one door. The
rejection now lives in the parse, reaches both, and carries the wrap
instruction. The guard stays for what strict cannot see: `defineView({})`.
Three shapes deliberately left open, each with its reason in the file rather
than a silent skip: `FormSectionSchema` (already closed with its own error map
and a transform), `UserFiltersSchema` (deliberately strips page-only keys, with
a test asserting it — changing that needs its own verification), and the
flattened Studio overlay in `ViewMetadataSchema`, which must stay open.
That last one is the `.extend()` trap the ledger warned about: closing
`ListViewSchema`/`FormViewSchema` silently closed the overlay too, turning a
shape the platform itself writes into a 422. Both `.strip()` back. It was caught
by a test whose name is the whole contract — someone wrote "preserves auxiliary
Studio round-trip keys without a strict-mode 422" before this campaign existed.
The container's `name`, `label` and `object` were tombstoned in the first draft
and should not have been: the platform writes all three. Fourth false guidance
claim in three batches. What fixed it was not more care but a different method —
scan every real payload of the shape in the repo and keep only the entries no
real payload contradicts. Six of nine survived. A tombstone asserts "nothing
legitimately writes this key", which is an empirical claim, and the codebase can
be asked.
`view` is the end state, not the last item of debt: its registered schema is a
union of three runtime shapes and a union is only as closed as its most open
member — the Studio overlay, a wire shape wearing the same type name. So the
campaign finishes at 24 of 25 closed with the 25th a documented permanent
exception, recorded beside the reverse pin so nobody closes it by force.
Verified: full monorepo suite 132/132 tasks green, spec 7241 tests, tsc clean,
8 generated artifacts current, all 10 spec gates green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY
os-zhuang
marked this pull request as ready for review
August 1, 2026 21:34
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-zhuang
enabled auto-merge
August 1, 2026 21:34
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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.
#4001 最后一批(清单)。批 1–6d = #4514 → #4533,均已合并。
为什么 view 最会藏
视图是作者用眼睛迭代的那个面——所以一个被丢弃的键在这里最隐蔽:视图照样渲染,只是不是他描述的那个样子。
FormFieldBase/FormSection/FormButtonConfig早在 ADR-0089 D3a 就关了。文件里另外四十多个形状,保持的正是那三个当年被救出来的姿态。defineView的守卫,是第五个「只守一扇门」的补丁它的注释自己写着理由:
这是本战役找到的第五个为绕开静默剥离而建的 bespoke 守卫,而且和前四个一样——它只守了
defineView这一扇门。走元数据门(Studio / API / agent)的,拿到的是一个静默的空容器。现在拒绝在解析层,两扇门都覆盖,而且带上「该怎么包起来」的指令。守卫留着,管 strict 看不见的那个 case:
defineView({})——没有未知键,照样零视图注册。三处刻意不转,每处都把理由写进文件
FormSectionSchemastrictVisibilityError和归一化.transform()。转换 = 重写可用且有测试的行为UserFiltersSchematabs/showAllRecords,有测试钉着。改成拒绝需要单独验证——这批没验证就不动,点名留在文件里isPinned/sortOrder等往返键,saveMetaItem原样持久化第三处正是账本预告过的
.extend()陷阱:.extend()继承 strictness,关闭ListViewSchema让这个 overlay 静默变严——对平台自己写入的形状 422。抓到它的是一个测试的名字:
有人在这场战役存在之前,就精确命名了未来某次收紧会造成的失败。
action.permissions「没有权限键」requiredPermissions有,403 强制——照做会删掉一个正在工作的门action.location→locationsview.name/view.label@objectstack/objectqlview.objectgetViewsByObject()读它@objectstack/cli没有一次是靠写 schema 时发现的。
最后管用的不是「更小心」,是换方法:把仓库里每一个真实的 container 载荷扫一遍,只保留没有任何真实载荷反驳的 guidance 条目。九条活六条,杀三条——一条命令,而且能在第一次 CI 红之前抓到全部四个。
推论两条,已写进账本:拒绝信息里的散文是行为,不是文档(一条自信地写错的比没有更糟,因为作者没有理由怀疑它);关闭一个注册类型的影响半径是每一个解析那个类型的包。
🏁
view是终点,不是最后一笔欠债注册的
view是三个运行时形状的 union,union 的严格程度取决于它最开放的成员——那个成员就是上面那个 Studio overlay,一个穿着同一个类型名的 wire 形状。所以战役停在 24 / 25 关闭,第 25 个是有据可查的永久例外。这段写在反向钉旁边,免得后来者「为了凑齐」硬把它关上。
关掉的是作者写的全部;留开的,正是账本开头那条分类规则要划的线——在最后一步以答案的身份出现,而不是以例外的身份。
战役结账
一个为「警告 strip 模式元数据」而建的层,几乎没有东西可警告了——那是棘轮走到头。 它的测试在原地写着:把下限改成 0 并刻意断言空集,永远不要删掉这个测试——因为一个没人选择的空结果,和一个坏掉的推导,长得一模一样。
验证
@objectstack/spec:7241 用例,tsc --noEmit干净check:*全绿object= live 附消费者;name/label= dead 的 body 键,行上的列才是活的)授权影响:这些形状没声明的键从「静默丢弃」变成「拒绝」——本来就已经被忽略。
🤖 Generated with Claude Code
https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY
Generated by Claude Code