Repository navigation
Commit 607d3bb
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBAakEo5aeRDTLTgR7gcMAuq)_
Part of #25923 (work item 4 only; item 3 and the FormField follow-up
stay on the card)
Clause-②: yes (narrowing)
Metadata-protocol: narrowed
Skills-docs: none — `skills/objectstack-ui/references/react-blocks.md`
already teaches `contentLayout` and `confirmOnDiscard`; object-calendar
`locale` and `loading` are taught only by the spec rows' `.describe()`
text, with no `skills/**` or `ui/content/docs` page; no `skills/**` page
names the zod `ActionSchema`, and the two ui docs pages that imported it
are updated in this diff
## 维护者速读
1. 卡面"33 个 spec-only 键"实测是同名碰撞:spec `ActionSchema` 对 objectui 无关的旧
`type: 'action'` 节点 schema。真实配对上的缺口是 11 个键。
2. 4
个有渲染器读取的键按引用派生:`ObjectFormSchema.contentLayout`/`confirmOnDiscard`、`ObjectCalendarSchema.locale`/`loading`(均为节点键,不是
#26411 移走的日历字段名键)。
3. 其余 7 个是 `FormFieldSchema` 上 spec 表单视图条目的键(两层同名词汇),逐键登记在
`zod-mirror-parity.test.ts` 的普查里:2 translated、4 carried-not-rendered、1
spec-retired。
4. `@object-ui/types/zod` 的 `ActionSchema` 改名 `CRUDActionSchema`:0
个生产导入方,改名比退役破坏最少;接受集不变。
5. 收窄:旧导出名消失,宽容面对 4 个键的坏值现在按 spec 拒绝 ⇒ `Clause-②: yes
(narrowing)`、`Metadata-protocol: narrowed`,changeset 带 BREAKING
Before/Now/Fix。
6. 门禁:dispatch-gates 34/34 exit 0 已对账;ui
vitest(types、plugin-form、plugin-calendar)660/660 文件通过;依赖
`@object-ui/types` 的 39 个包 type-check 108/108 通过。
## Measurement (main `43731031`)
The key-drift probe pairs each `@object-ui/types/zod` mirror with the
spec schema of the same export name in `@objectstack/spec/data` ∪
`@objectstack/spec/ui`, and each node mirror with its
`ComponentPropsMap` row by `type` literal. A key the spec declares that
the mirror neither declares nor refuses is "spec-only".
| Pair | Spec-only keys on main | Note |
|---|---|---|
| `ActionSchema` ↔ spec `ActionSchema` | 33 | Not a pair: objectui's
`ActionSchema` is the legacy `type: 'action'` node and shares no
vocabulary with the spec's action metadata. This is the card's "33". |
| `FormFieldSchema` ↔ spec `FormFieldSchema` | 7 | Two layers under one
name (runtime field vs form-view entry) |
| `ObjectFormSchema` ↔ `ComponentPropsMap['object-form']` | 2 | |
| `ObjectCalendarSchema` ↔ `ComponentPropsMap['object-calendar']` | 2 |
|
| every other pair | 0 | |
Real gap over the real pairs: **11 keys**. After this PR: **0
unrecorded**, judged by the new census in `zod-mirror-parity.test.ts`.
## Per-key disposition
| Key | Disposition | Where |
|---|---|---|
| `ObjectFormSchema.contentLayout` | derived by reference
(`SpecObjectFormProps['contentLayout']`, zod `.shape.contentLayout`) |
`ModalForm` reads it |
| `ObjectFormSchema.confirmOnDiscard` | derived by reference |
`ModalForm`, `DrawerForm` read it |
| `ObjectCalendarSchema.locale` | derived by reference |
`plugin-calendar` `resolveAuthoredLocale(rest.locale)` |
| `ObjectCalendarSchema.loading` | derived by reference |
`plugin-calendar` `resolveExternalLoading(rest.loading)` |
| `FormFieldSchema.field` | recorded: translated |
`normalizeSectionField` writes it as the runtime `name` |
| `FormFieldSchema.helpText` | recorded: translated | written as the
runtime `description` |
| `FormFieldSchema.immutable` | recorded: declared, not rendered |
copied onto the runtime field; no renderer reads it |
| `FormFieldSchema.keyField` | recorded: declared, not rendered | copied
through for the record widget; no widget reads it yet |
| `FormFieldSchema.disclosure` | recorded: declared, not rendered |
copied through for composite widgets; no widget reads it yet |
| `FormFieldSchema.precision` | recorded: declared, not rendered |
number widgets read `scale` and the object field's metadata |
| `FormFieldSchema.publicPicker` | recorded: spec-retired | the spec's
own `retiredKey()` tombstone refuses it with its remedy |
No key needed a new `z.never` refusal: the only retired key
(`publicPicker`) is already refused by the spec with its remedy, and
objectui's runtime layer never had it.
Seat guard on the two calendar keys: `locale` and `loading` are members
the spec authors on the `object-calendar` node and the renderer reads
off the node. They are not the calendar field-name keys PR #26411 moved
to the hand-off type, so nothing returns to the published face that item
1 took off it.
## ActionSchema: rename, not retire
Importers of the zod `ActionSchema` on main: **0 production**, 7 test
files, 2 docs pages. Retiring it would also break the `action` arm of
the CRUD discriminated union and the `actions` arrays of
`CRUDDialogSchema`, `DetailSchema` and the chain, which all hold it.
Renaming changes only the export name, so it breaks fewest. The
TypeScript twin keeps its deprecated `ActionSchema` name in
`@object-ui/types`.
## What changes
- `ui/packages/types/src/zod/objectql.zod.ts`,
`ui/packages/types/src/objectql.ts`: the four keys, by reference on both
faces; `ObjectFormSlotKey` carries the two form keys.
- `ui/packages/types/src/zod/crud.zod.ts`, `index.zod.ts`:
`ActionSchema` → `CRUDActionSchema`, every internal reference with it.
- Tests: the seven test importers renamed;
`object-view-slot-key-lists.test.ts` pins `ObjectFormSchema` at 71
members (was 69).
- Docs: the two pages that import the const.
- `.changeset/25923-spec-only-keys-crud-action-schema.md`:
`@object-ui/types` minor, BREAKING Before/Now/Fix.
## Tests
`zod-mirror-parity.test.ts` is extended (no new gate) with a census,
"every spec-only key over the spec pairs is derived, refused or
recorded":
- no spec-only key without a row; no dead row; every reason at least 40
characters;
- non-vacuity: the derived pairs include the four named above;
- identity pins for the four derived keys, and `contentLayout: 'tabs'`
refused at path `contentLayout`;
- the zod barrel has no `ActionSchema` and has `CRUDActionSchema`, while
`@objectstack/spec/ui` still has `ActionSchema`.
Reverse check: removing the `contentLayout` derivation turns the census
red naming `ObjectFormSchema.contentLayout`; restored afterwards.
## Acceptance notes
- `immutable`, `keyField`, `disclosure` and `precision` are copied by
`normalizeSectionField` but no renderer reads them. That is recorded
here as "declared, not rendered"; no reach was measured, so no card is
filed for it.
- ADR-0087 disposition is `not-required (no-migration-prescription)`.
`runtime-export-retired` would fit better, but that category reads only
a package's main entry and refuses an operand declared in a `*.zod.ts`,
and this export is on the `./zod` subpath.
- **ADR-0087 marker (seat ruling, 2026-10-27):** `not-required
(no-migration-prescription)` stands, as on PR #26411. The gate cannot
see `@object-ui/types` exports yet, and #26220 (`PACKAGE_ROOTS` omits
`ui/packages`) carries that gap.
- **`immutable` is declared on the mirror but not rendered by objectui**
(contract review 6445632813 ③.5). It folds into #25923's FormField
follow-up and is recorded on the card at landing.
## Verification
Head `38c2841a` (readings below were taken on `96c8d55d`, with `main`
`94bab5a2` merged in; `d18ba32e` adds a reasoned
`eslint-disable-next-line no-restricted-imports` on the census's `import
* as SpecUi from '@objectstack/spec/ui'`, the form
`spec-ui-schema-reexports.test.ts` uses, which turned Lint UI green;
`38c2841a` corrects `enhanced-actions.mdx` to name `CRUDActionSchema`).
The vitest, gates and type-check readings below were taken at `b5f1b90b`
(before the merge); after the merge, `@objectstack/spec` was rebuilt and
`cd ui && pnpm exec vitest run packages/types/` re-run under
os-verify-lock: 393/393 files, 10691 passed, exit 0. #26365 is still an
open draft; it edits `zod-mirror-parity.test.ts` in different regions,
and whichever lands later merges `main` and re-runs that file.
- `node scripts/pm/dispatch-gates.mjs --ran`: 34 derived, 34 run, 0
NOT-MEASURED; every exit 0. `pnpm --dir ui exec vitest run scripts/`
first exited 1 on an unbuilt `@objectstack/core` dist in this container,
and exited 0 once it was built.
- Under os-verify-lock, `cd ui && pnpm exec vitest run packages/types/
packages/plugin-form/ packages/plugin-calendar/`: 660/660 files, 13570
passed, 96 skipped, exit 0.
- Under os-verify-lock, `cd ui && pnpm exec turbo run type-check
--filter='...@object-ui/types' --concurrency=2 --continue`: 39 packages
in scope, 108/108 tasks successful, exit 0.
- `node scripts/check-platform-checklist.mjs --changed-from
origin/main`: exit 0 (no anchored file in the change set).
- `node scripts/check-adr-0087-registration.mjs --base origin/main`:
exit 0.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01WGufzhgTn8yFwqXxanJd4c
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent d31329f commit 607d3bb
15 files changed
Lines changed: 314 additions & 52 deletions
File tree
- .changeset
- ui
- content/docs
- core
- guide
- packages/types/src
- __tests__
- zod
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
301 | 301 | | |
302 | 302 | | |
303 | 303 | | |
304 | | - | |
305 | | - | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
306 | 307 | | |
307 | 308 | | |
308 | 309 | | |
| |||
483 | 484 | | |
484 | 485 | | |
485 | 486 | | |
486 | | - | |
| 487 | + | |
487 | 488 | | |
488 | 489 | | |
489 | 490 | | |
| |||
492 | 493 | | |
493 | 494 | | |
494 | 495 | | |
495 | | - | |
| 496 | + | |
496 | 497 | | |
497 | 498 | | |
498 | 499 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
| 190 | + | |
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
108 | | - | |
| 108 | + | |
109 | 109 | | |
110 | | - | |
| 110 | + | |
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
| |||
120 | 120 | | |
121 | 121 | | |
122 | 122 | | |
123 | | - | |
| 123 | + | |
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
| |||
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
160 | | - | |
| 160 | + | |
161 | 161 | | |
162 | 162 | | |
163 | 163 | | |
| |||
171 | 171 | | |
172 | 172 | | |
173 | 173 | | |
174 | | - | |
| 174 | + | |
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
178 | 178 | | |
179 | 179 | | |
180 | 180 | | |
181 | | - | |
| 181 | + | |
182 | 182 | | |
183 | 183 | | |
184 | 184 | | |
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
189 | | - | |
| 189 | + | |
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
194 | 194 | | |
195 | 195 | | |
196 | | - | |
| 196 | + | |
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
200 | 200 | | |
201 | | - | |
| 201 | + | |
202 | 202 | | |
203 | 203 | | |
204 | 204 | | |
| |||
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
215 | | - | |
| 215 | + | |
216 | 216 | | |
217 | 217 | | |
218 | 218 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
98 | | - | |
| 98 | + | |
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
| |||
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
202 | | - | |
| 202 | + | |
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | | - | |
74 | | - | |
| 73 | + | |
| 74 | + | |
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
160 | | - | |
| 160 | + | |
161 | 161 | | |
162 | 162 | | |
163 | 163 | | |
| |||
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
194 | | - | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
292 | 292 | | |
293 | 293 | | |
294 | 294 | | |
295 | | - | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
296 | 299 | | |
297 | | - | |
| 300 | + | |
298 | 301 | | |
299 | 302 | | |
300 | 303 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
364 | 364 | | |
365 | 365 | | |
366 | 366 | | |
367 | | - | |
| 367 | + | |
368 | 368 | | |
369 | 369 | | |
370 | 370 | | |
| |||
378 | 378 | | |
379 | 379 | | |
380 | 380 | | |
381 | | - | |
| 381 | + | |
382 | 382 | | |
383 | 383 | | |
384 | 384 | | |
| |||
394 | 394 | | |
395 | 395 | | |
396 | 396 | | |
397 | | - | |
| 397 | + | |
398 | 398 | | |
399 | 399 | | |
400 | 400 | | |
| |||
408 | 408 | | |
409 | 409 | | |
410 | 410 | | |
411 | | - | |
| 411 | + | |
412 | 412 | | |
413 | 413 | | |
414 | 414 | | |
| |||
427 | 427 | | |
428 | 428 | | |
429 | 429 | | |
430 | | - | |
| 430 | + | |
431 | 431 | | |
432 | 432 | | |
433 | 433 | | |
| |||
462 | 462 | | |
463 | 463 | | |
464 | 464 | | |
465 | | - | |
| 465 | + | |
466 | 466 | | |
467 | 467 | | |
468 | 468 | | |
| |||
492 | 492 | | |
493 | 493 | | |
494 | 494 | | |
495 | | - | |
| 495 | + | |
496 | 496 | | |
497 | 497 | | |
498 | 498 | | |
| |||
516 | 516 | | |
517 | 517 | | |
518 | 518 | | |
519 | | - | |
| 519 | + | |
520 | 520 | | |
521 | 521 | | |
522 | 522 | | |
| |||
549 | 549 | | |
550 | 550 | | |
551 | 551 | | |
552 | | - | |
| 552 | + | |
553 | 553 | | |
554 | 554 | | |
555 | 555 | | |
| |||
573 | 573 | | |
574 | 574 | | |
575 | 575 | | |
576 | | - | |
| 576 | + | |
577 | 577 | | |
578 | 578 | | |
579 | 579 | | |
| |||
590 | 590 | | |
591 | 591 | | |
592 | 592 | | |
593 | | - | |
| 593 | + | |
594 | 594 | | |
595 | 595 | | |
596 | 596 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | | - | |
| 107 | + | |
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
| |||
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
146 | | - | |
| 146 | + | |
147 | 147 | | |
148 | 148 | | |
149 | 149 | | |
| |||
0 commit comments