Skip to content

feat(spec)!: 收紧 responsive/SDUI 样式形状的未知键,并把另外五个文件按实测改判(#4001 批 13) - #5003

Merged
xuyushun441-sys merged 3 commits into
mainfrom
claude/issue-4001-ui-batch13
Aug 3, 2026
Merged

feat(spec)!: 收紧 responsive/SDUI 样式形状的未知键,并把另外五个文件按实测改判(#4001 批 13)#5003
xuyushun441-sys merged 3 commits into
mainfrom
claude/issue-4001-ui-batch13

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Part of #4001 —— ui/ 方向的第一波(批 13),六个交互/呈现配置文件,账本重测记的 ~26 个 strip 站点。

结论先说:6 个文件里只有 1 个该收紧

批 13 的六个文件账本上全是 authorable (p) —— (p) 是待验证,不是结论。逐个解 (p) 之后:

文件 站点 (p) 解出来是 本 PR 做了什么
responsive.zod.ts 4 可授权,且门是活的 ✅ 4 个站点全部 strictObject
touch.zod.ts 7 没有授权门 改判 class + 三处记录,不收紧
animation.zod.ts 4 同上 同上
dnd.zod.ts 4 同上 同上
keyboard.zod.ts 4 同上 同上
offline.zod.ts 3 同上 同上

批 10(state-machine)和批 11(webhook)解 (p) 时都找到了账本没记的门,这留下一个「验证 = 找门」的隐含预期。批 13 用同一套程序、同一次运行里带阳性对照,连着五个文件没找到任何门 —— 而验证步骤的正确输出就是它测到的东西,包括「这从来就不是棘轮的活」。

一、responsive.zod.ts —— 收紧的那一个

(p) 解在图上而不是在文件表面:page.components[].responsive / .responsiveStyles 把两个形状放进了 page 这个 metadata-type root。(dashboard.widgets[].responsive 是第二个承载键,同日被 #4876 退役,本 PR 已合并其变更并联测。)

收紧真正补的是一个嵌套洞。 PageComponentSchema 自 ADR-0089 D3a 起就是 .strict(),而严格性不递归,所以这个组件在 main 上解析是干净通过的:

PageComponentSchema.parse({
  type: 'element:text', id: 't1',
  responsiveStyles: { lg: { fontSize: '40px' } },
  responsive: { colums: { lg: 4 }, hideOn: ['xs'] },
})
// → { …, responsiveStyles: {}, responsive: {} }

作者写的每一条样式和布局指令,全没了,报告有效。一个 strict 的壳套着 strip 的子块,不是一个关上的面,是关上的面的剪影。

策展锚在同文件的兄弟契约上,不是编辑距离(批 12 的方法)

这个文件在同一个页面组件上、相隔十六行载着两套断点词汇:responsiveStyles 是 ADR-0065 的 desktop-first 桶(large/medium/small/xsmall),responsive 是文件顶部 BreakpointName 的 Tailwind 阶梯(xs2xl)。两套都对,互相不是错别字,编辑距离也过不去(lglarge)。所以别名双向都配。

两条是测出来的,不是推出来的:

  1. { columns: { large: 4, lg: 3 } } 过去会保留一半的 map —— 节点确实布局了,在错误的宽度上、在作者从没点名的断点上。这比全丢更坏,全丢至少是看得见的。
  2. hideOnhiddenOn 必须手写别名,因为兜底证明够不着:findClosestMatches 把输入小写化、候选不小写化,于是声明键里每个大写字母白扣一次编辑距离 —— hideOn 对预算 2 算出 3,而全小写的 hiddenon 算出 1 反而给得出建议。这条不对称对 camelCase 键是普遍的(按 AGENTS.md 命名约定,即 spec 的绝大多数键),单独归档为 未知键的「你是不是想写」兜底对 camelCase 键系统性偏弱:输入被小写化、候选没有 —— 每个大写字母白扣一次编辑距离 #4990

两条是处方而非改名:responsive 层上的裸断点名(退役的 view.responsive 那套 breakpoint-keyed 形状,#3896;转换注册表里还留着 responsive: { sm: {} } 这个 fixture)三个键都可能是目标,所以逐键给独立文案 —— guidance 每个键原样发一条 bullet,共享字符串会把同一段打印 N 次(批 10 join/joinGateway 的教训)。以及两套词汇互相写错时,指向同组件上的兄弟键。

StyleMapSchema 故意保持开放(键空间是每一个 CSS 属性,objectui 的 declarations() 拿到什么就 kebab 化发什么),按批 12 标准记在三处:schema JSDoc、测试 pin、账本行。

二、另外五个文件 —— 22 个站点,实测没有授权门

三条独立测量(2026-08-03,均带阳性对照):

  1. 静态 —— packages/spec/src 里除 ui/index.ts barrel 外没有任何模块 import 它们;协议里不存在 component.touch / page.dnd / app.motion 这类承载键。
  2. 图可达性 —— 从 24 个 metadata-type root 加 defineStackObjectStackSchema 做 BFS(build-schemas.tsauthorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 删除检查用的同一套闭包),6849 个节点,22 个站点一个都没走到。同一次运行里三个阳性对照全部 root-graph:PageSchema、批 11 的 WebhookSchema、批 10 的 StateMachineSchema对照通过,所以「不可达」是关于图的事实,不是仪器坏了。
  3. 调用点 —— 三个仓库里除各自单测外没有任何 .parse()。objectui 只 re-export 推断类型,并明确说不 re-export 校验器([umbrella][security] 授权全生命周期缺口地图 — 包开发 → 生产上线(P0–P3) #2561)。

.strict()parse 的属性,而这里没有 parse。收紧它们不拦任何东西,只会花掉一次 v17 破坏性变更让文件看起来完成,并留下账本自己警告过的东西 —— 「一个被精确校验的死槽位是更有说服力的谎言」#4583 那一行)。真正该判的是 ADR-0049 enforce-or-remove,已归档 #4988

每个文件按批 12 标准三处留痕(文件头注释 + 测试 pin + 账本行),并且 pin 是会红的:每个文件都有一条「除 barrel 外无 import 者」断言,谁给这套词汇接上承载键,那条就变红并把人指回 #4988

三、仪器自证(每一类新断言都先证红,再信绿)

破坏 应红的断言 结果
抽掉 ResponsiveStyles 整张别名表 两套词汇互映 ✅ 红
把逐键 guidance 换成共享字符串 「逐个点名而不是一次带过」 ✅ 红
删掉 hideOn 别名 两种错拼都到达 hiddenOn ✅ 红
同上 嵌套路径而非组件层报错 ✅ 红
touch.zod 加一个真实承载 import 「除 barrel 外无 import 者」 ✅ 红,并点名 ui/component.zod.ts
DragConstraintSchema 关上 「仍然 strip,故意的」 ✅ 红
账本 header 改成 120 check:strictness-ledger 算术 ✅ 红(rows sum to 119)

其中一次破坏抓到了我自己的仪器欠缺:import 者 pin 一开始只匹配 from '…',barrel 用的是 export * from,而裸副作用 import 两者都不是 —— 先红后绿这一步不做,这条 pin 会以一个部分空洞的绿落地。已改成三种形式都匹配。

四、ADR-0087 示例应用验证(附一条要紧的发现)

按槽位溯源解析三个应用的构建产物(批 12 的警告:这两个形状全 optional,{} 能过,按形状匹配的走法会「找到」成千上万个无关对象、给出一个毫无意义的绿。所以只解析真实承载槽位上的值):

app-showcase    139 authored slot(s) at a real carrier, 0 rejected
app-crm           0 ...
app-todo          0 ...
TOTAL 139 slots parsed against the new contracts, 0 rejected

三个应用 validate 全过(exit 0,零 error)。

⚠️ 但阴性对照在 validate 上没红,这本身是个发现。responsiveStyles.large 改成 .lg 注入源码后,objectstack buildvalidate 都通过,坏键还写进了产物。查下去发现:这条路根本不按 PageSchema 解析页面元数据 —— 一个 PageComponentSchema 自 ADR-0089 D3a 起就拒绝的键同样一路通过。也就是说 #4001 各批验收里那条「三个示例应用 validate 全过」对 page 面是恒真的空证。已归档 #5000

本 PR 的阴性对照因此走真门,并且是红的:

getMetadataTypeSchema('page')  ← MetadataManager.validate / GET /api/v1/meta / Studio 表单
  clean (control)                            ACCEPTED
  crossed vocabulary                         REJECTED — `lg` …
  legacy breakpoint-keyed                    REJECTED — `sm` …
  pre-existing strict violation (ADR-0089)   REJECTED

这条「门在哪」的测量结果记进了 responsive.zod.ts 的文件头 —— 收紧不该声称自己没有的触及面。

五、账本

验证

归档的范围外发现(均未指派)

变更集:.changeset/unknown-key-strictness-ui-batch13.md(major,v17 rc 窗口)。

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9


Generated by Claude Code

claude added 3 commits August 3, 2026 19:10
#4001 批 13)

Close all four sites in `ui/responsive.zod.ts` with `strictObject`. The nested
gap is what this fixes: `PageComponentSchema` has been `.strict()` since
ADR-0089 D3a and strictness does not recurse, so a component whose every styling
and layout instruction was written in the wrong breakpoint vocabulary parsed
clean and returned `{ responsiveStyles: {}, responsive: {} }`.

The file carries TWO breakpoint vocabularies sixteen lines apart on the same
component (ADR-0065 buckets vs the Tailwind ramp), so the aliases run both ways
and are anchored to the named sibling rather than to edit distance.

The other five files in this batch are NOT closed, on a measurement: their 22
sites have no authoring door (no carrier key; unreachable by BFS from all 24
metadata-type roots plus defineStack, with three positive controls passing in
the same run; no .parse() anywhere in three repos). ADR-0049 triage is #4988.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9
…tness (#4001 批 13)

The door is getMetadataTypeSchema('page') — MetadataManager.validate, GET
/api/v1/meta, the Studio page form. It is NOT objectstack build/validate: a key
PageComponentSchema has rejected since ADR-0089 D3a passes both and lands in the
built artifact. Pre-existing, filed as #5000; recorded here so the campaign's
usual "three example apps validate" line is not read as evidence for this
surface.

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

vercel Bot commented Aug 3, 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 3, 2026 7:59pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests protocol:ui tooling size/xl labels Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

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.

@xuyushun441-sys
xuyushun441-sys marked this pull request as ready for review August 3, 2026 20:02
@xuyushun441-sys
xuyushun441-sys added this pull request to the merge queue Aug 3, 2026
Merged via the queue into main with commit 7055c22 Aug 3, 2026
25 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the claude/issue-4001-ui-batch13 branch August 3, 2026 20:21
xuyushun441-sys pushed a commit that referenced this pull request Aug 4, 2026
Brings in #5003 (批 13), #5006, #4983, #4991, #4855, #4729, #4250.

Ledger `ui/` section conflicted, as planned — 批 13 and 批 14 both edit it. Every
row from both sides kept; nothing resolved in favour of a side:

  - classification table: ONE merged `no door` row (批 13 authored the class;
    批 14 adds the positive-control requirement and the first file that SPLITS
    across it, ui/sharing.zod.ts).
  - triage table: structure from 批 13 (it split `responsive` out and grouped the
    five no-door files); 批 14's four measured verdicts overlaid.
  - remaining-strip map: `responsive` row deleted by 批 13, `action`/`report`/
    `dataset`/`dashboard` rows deleted by 批 14 — all five by the reverse pin.

Header and subtotal RECOMPUTED FROM THE SURVIVING ROWS, not decremented:
29+20+14+9+7+7+6+4+4+4+3+1+1+1 = 110. 批 13 wrote 119 (against a tree where 批 14's
four rows still existed), 批 14 wrote 114 (against one where `responsive` still
did); both were right against their own branch and both are wrong against the
merge. The fifth and sixth instances of the failure the automation/ section
documents, and the first where the two wrong numbers were both this line. Subtotal
88 of 110 authorable, 22 in the fourth class. check:strictness-ledger arbitrates
and is green.

os-regen four-step: merged (never rebased), refreshed install + spec build, reset
all seven generator-owned paths to origin/main, regenerated wholesale. Delta vs
origin/main is exactly one file — content/docs/references/ui/sharing.mdx — so the
regeneration reproduced main's artifacts byte-identically and no sibling entry was
dropped (#5006's RateLimitConfig/RateLimitConfigSchema and 批 13's responsive
entries confirmed present).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9
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 protocol:ui size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants