Skip to content

Commit 785a748

Browse files
feat(spec)!: tighten unknown keys on nine ui/ shapes, reclassify two as no-door (#4001 批 14) (#5042)
Eleven strip sites measured per the #4852 remeasure; the counts held exactly (1+1+2+2+3+2, confirmed against the ledger gate's own AST counter). Per-schema door measurement then split them nine / two. Closed with strictObject: ui/action.zod.ts ActionParamSchema.options[] ui/sharing.zod.ts SharingConfigSchema ui/report.zod.ts ReportSortSchema, JoinedReportBlockSchema ui/dataset.zod.ts DatasetDimensionSchema, DatasetMeasureSchema, .derived ui/dashboard.zod.ts DashboardWidgetSchema.compareTo (object arm), .layout Four of those are strict shells over strip children: the container was already strict and strictness does not recurse. An action param option carrying color/visibleWhen/icon/disabled parsed clean through getMetadataTypeSchema('action') and came back {label, value}. Reclassified as the fourth class (no door), NOT tightened: ui/notification.zod.ts NotificationActionSchema ui/sharing.zod.ts EmbedConfigSchema Both measured three ways with positive controls in the same run: no carrier key, unreachable in a 6860-node BFS from the 24 metadata-type roots + defineStack, zero parse outside their own tests. Injecting a synthetic carrier flipped both, so the verdict is a fact about the graph rather than a broken walker. sharing.zod.ts is the ledger's first file that splits across the class. action's option entry goes strict rather than following bulk-action's .passthrough() (#4909): measured, not inherited. That def reaches the grid verbatim with no spec door and objectui's BulkActionParam declares an explicit index signature; this path has a door that already strips and lands in the CLOSED SelectOptionMetadata. Curation anchored on named sibling contracts, not edit distance: dataset on the Cube layer this module's header names (a Cube metric's `type` IS its aggregation), report's order key on SortNodeSchema and the widget's flat sortBy/sortOrder, layout on React-Grid-Layout. Known reach limit, measured: compareTo is a union, so its prescription is produced but not delivered (zodIssuesToFields maps only top-level issues; #5014). The rejection is unaffected. Tests pin both halves separately. Out-of-scope findings filed unassigned: #5013 (ReportSchema's `filter` alias prescribes `filters`, which it also rejects, plus 5 dead entries), #5014, #5015 (ADR-0049 verdict for the two no-door shapes), #5016 (should action options carry the field-level per-option vocabulary). Claude-Session: https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9 Co-authored-by: Claude <noreply@anthropic.com>
1 parent a019e52 commit 785a748

10 files changed

Lines changed: 1323 additions & 70 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
"@objectstack/spec": major
3+
---
4+
5+
feat(spec)!: 收紧 action param 选项、公开分享、报表排序、数据集语义层与仪表盘小组件的嵌套未知键(#4001 批 14)
6+
7+
`ui/` 方向第二波。账本重测记的 11 个 strip 站点,逐个做门测量后:**9 个收紧,2 个改判**
8+
9+
## 破坏性变更 —— 9 个形状不再静默丢弃未知键
10+
11+
| 形状 | 文件 | 之前 |
12+
|---|---|---|
13+
| `ActionParamSchema.options[]` | `ui/action.zod.ts` | `{ label, value }` 之外的键被剥 |
14+
| `SharingConfigSchema` | `ui/sharing.zod.ts` | 同上 |
15+
| `ReportSortSchema` · `JoinedReportBlockSchema` | `ui/report.zod.ts` | 同上 |
16+
| `DatasetDimensionSchema` · `DatasetMeasureSchema` · `.derived` | `ui/dataset.zod.ts` | 同上 |
17+
| `DashboardWidgetSchema.compareTo`(对象分支)· `.layout` | `ui/dashboard.zod.ts` | 同上 |
18+
19+
**升级方式:把被拒的键改成错误信息点名的那个。** 拒绝本身就带处方 —— 它点名面、原样回显写错的键,并在可能时给出规范拼法。没有任何键被移除,也没有任何合法形状变得不合法:这些 schema 接受的键集合完全没变,变的只是「写了别的会怎样」。
20+
21+
其中四个是 **strict 外壳套 strip 子块** —— 容器早就 strict,但**严格性不递归**
22+
23+
- `ActionParamSchema`#3746 起 strict,而它的 `options[]` 条目不是。实测一个带 `color` / `visibleWhen` / `icon` / `disabled` 的选项过 `getMetadataTypeSchema('action')`,出来是 `{"label":"Overload","value":"overload"}` —— 四个键在任何 renderer 看到之前就没了,报告成功。
24+
- `DashboardWidgetSchema` 自 ADR-0021 起 strict,而 `compareTo` 的对象分支和 `layout` 不是。
25+
- `DatasetSchema` / `ReportSchema` 同理,漏的正是承载语义契约的那几个子形状。
26+
27+
### 为什么 `action` 的选项走 strict,而兄弟 `bulk-action``.passthrough()`
28+
29+
两边不同是**测出来的,不是照搬的**#4909 给 bulk-action 选项条目 `.passthrough()` 的两条理由在这里都不成立:那边的 def「left as-authored」逐字到达 grid(中间没有 spec 门),且 objectui 的 `BulkActionParam` 声明了显式 `[key: string]: unknown` 兜底;这边有一道**已经在剥**的门,落点是**封闭**`SelectOptionMetadata` 接口。目标词汇封闭,正是「声明」胜过「容忍」的场合。action param 选项是否该讲字段级的逐选项词汇,是独立的能力问题(#5016),不在本批猜。
30+
31+
## 两个形状改判为第四类 `no door`****收紧
32+
33+
`NotificationActionSchema``ui/notification.zod.ts`)与 `EmbedConfigSchema``ui/sharing.zod.ts`**没有授权门**:没有承载键、从 24 个 metadata-type root + `defineStack` 做 BFS(6860 节点)不可达、三个仓里除自测外零 `.parse()`。收紧它们会花掉一次破坏性变更去留下「一个被精确校验的死槽位 —— 更有说服力的谎言」。ADR-0049 定去留:#5015
34+
35+
`ui/sharing.zod.ts` 是账本第一个**一行两判**的文件:同一文件里 `SharingConfig` 是活门(`FormViewSchema.sharing` 承载,`rest-server.ts``sharing.allowAnonymous` + `sharing.publicLink` 挂匿名表单路由,两个示例应用都在写),`EmbedConfig` 没有门。按文件下判断,无论落哪边都会错一半。
36+
37+
## 策展依据是同仓的兄弟契约,不是编辑距离
38+
39+
- **dataset** 锚在本模块自己 header 点名的 `data/analytics.zod.ts` Cube 层:Cube metric 的 `type` **就是**聚合函数,所以 `{ name: 'revenue', type: 'sum', field: 'amount' }` 过去 parse 干净、算出来是 `count``sql` 只给 guidance 不给别名 —— 把 `SUM(amount)` 指向吃字段路径的 `field`,是本战役自己要消灭的那种错误处方。
40+
- **report** 的排序键是作者会遇到的**第三种** sort 拼法(`SortNodeSchema``{field, order}`、小组件的扁平 `sortBy`/`sortOrder`、这里的 `{by, direction}`),而且映射方向相反,任何一种都推不出来。
41+
- **dashboard `layout`** 锚在 React-Grid-Layout:`minW`/`static`/`i` 等给逐键 guidance,而不是改名到无关的位置键上。
42+
- **sharing** 的别名全是 camelCase 目标,兜底系统性够不着(#4990)。`allowAnonymous` 写错拼法的后果是**表单保持私有而作者以为公开**
43+
44+
## 已知触及面限制(实测记录,非推断)
45+
46+
`compareTo` 是 union。zod 把失配 union 折叠成一条顶层 `invalid_union`(message 是裸的 `Invalid input`),分支错误挂在 `issue.errors`,而 `zodIssuesToFields` 只映射顶层 —— **处方产生了但送不到作者手上**。拒绝不受影响,这仍是 #4001 的收益。传输缺陷是 #5014,影响本战役放进 union 分支的每一条策展文案。测试对这两半**分开** pin,免得一个绿测试冒充一条没人打印的消息。

content/docs/references/ui/sharing.mdx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,31 @@ description: Sharing protocol schemas
99

1010
Sharing & Embedding Protocol
1111

12-
Defines schemas for public link sharing, embed configuration,
12+
Public-link sharing and iframe-embed configuration. The module name is
1313

14-
domain restrictions, and password protection for apps, pages, and forms.
14+
plural, but the two shapes below are in **opposite** postures, and #4001 批 14
15+
16+
measured why rather than assuming a file-level verdict:
17+
18+
- `SharingConfigSchema` has a **live authoring door**. `FormViewSchema.sharing`
19+
20+
carries it (`view.zod.ts`), `view` is a metadata-type root, and the runtime
21+
22+
really reads it: `rest-server.ts` mounts the anonymous form endpoints only
23+
24+
when `sharing.allowAnonymous === true` and a `sharing.publicLink` slug
25+
26+
matches. Both example apps author it (`app-showcase` `inquiry.view.ts`,
27+
28+
`app-crm` `lead.view.ts`). It is `strictObject` as of #4001 批 14.
29+
30+
- `EmbedConfigSchema` has **no door at all** — see its own block below.
31+
32+
That split is the point. The ledger's classification question is *"who writes
33+
34+
this schema's input?"*, and it is answered per SCHEMA, not per file; before
35+
36+
批 14 this file's row carried one verdict for both.
1537

1638
<Callout type="info">
1739
**Source:** `packages/spec/src/ui/sharing.zod.ts`

0 commit comments

Comments
 (0)