Repository navigation
Commit e843b5b
feat(types,react,sdui-parser)!: retire the node-level visibleOn / hiddenOn / disabledOn spellings (#26274)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbASAH4WuLBFpTWVCeQ9PHQu)_
Fixes #25926
Clause-②: no (narrowing)
Metadata-protocol: narrowed
## What changed
`@objectstack/spec` declares one conditional-visibility predicate at
every layer, `visibleWhen` (ADR-0089). objectui carried three spellings
of its own beside the spec's keys: `visibleOn` beside `visibleWhen`,
`hiddenOn` beside `hidden`, `disabledOn` beside `disabled`, each pair
evaluated by the same code with the same polarity. The three are
retired, immediately, with no alias window.
- **`@object-ui/types`** — `BaseSchema.visibleOn` / `hiddenOn` /
`disabledOn` are `?: never` tombstones on the TypeScript face and
`aliasKeyRefusal` arms on the Zod mirror (the `chartType` → `type`
shape). Each refusal names the key, the surviving key, the unchanged
polarity, and the remedy ("rename the key; the value is unchanged").
Boolean `visible` stays on `BaseSchema` (see Acceptance note 1).
- **`@object-ui/react`** — `SchemaRenderer`'s visibility chain is
`visibleWhen` / `visible` (SHOW legs, negated) and `hidden` (HIDE leg,
not negated); the enablement gate is `disabled` alone. A stale retired
key that reaches the renderer unvalidated is not consulted and is held
out of the component's props (the `body` treatment). The diagnostics'
key lists, the props-bag refusal and the fault copy follow.
- **`@object-ui/sdui-parser`** — the three leave `SDUI_BASE_PROPS`;
`validateTree` reports each as an `unknown-prop` diagnostic that names
the surviving key and says the spelling is retired
(`checkRetiredVisibilityDialect`, `RETIRED_VISIBILITY_DIALECTS`,
exported).
- **`@object-ui/cli`** — `objectui validate` reads the Zod mirror and
prints the tombstone (measured below). `objectui check` keeps the three
in `OBJECTUI_STRUCTURAL_KEYS` as identification markers, exactly as it
keeps `body` (objectui#6771): a file authored under a retired spelling
is still recognised and sent to `validate`; the sweep itself does not
parse recognised files (triage ruling objectui#11007).
- **`@object-ui/app-shell`** — the command palette reads a navigation
entry's `visible` only; the `?? item.visibleOn` fallback read a key
`NavigationItem` never declared.
- **Readers** (components form/action/disclosure renderers, core
`declaredPredicate` / `dom-props`, react diagnostics, plugin-chatbot,
`complex.ts`): comment-only, the retired spellings dropped from the
prose.
- **Tests** — the `hiddenOn` / `disabledOn` / `visibleOn` cases are
retired from 13 react/components/sdui-parser pins and the surviving
cases re-pointed; two new pins:
`node-visibility-dialects-retired.test.ts` (one `invalid_type` issue at
the key, message carries `Did you mean X → Y?`, `.describe()` equals the
message, `z.input` is `undefined`, both document faces refuse, canonical
spellings parse) and `SchemaRenderer.visibilityDialectsRetired.test.tsx`
(a stale key is not a leg and does not leak, each with a control on the
surviving key).
- **Skill + docs** — `skills/objectui/rules/protocol.md` and
`guides/schema-expressions.md` teach `visibleWhen` / `hidden` /
`disabled` (raw expression or `${}` template) and name the retired
spellings as refused; `ui/content/docs` `guide/expressions.md`,
`api/schema-reference.md`, `guide/schema-playground.md`, plus
`guide/schema-rendering.md`, `guide/metadata-diagnostics.md` and
`utilities/runner.mdx` (see deviation 1). The form field's view-level
`fields[].visibleOn` is a different slot and is left as it was, with a
sentence saying so.
- **Changeset** `.changeset/25926-retire-node-visibility-dialects.md`
(types / react / sdui-parser minor, app-shell patch; BREAKING; ADR-0087
`not-required (no-migration-prescription)` on the objectui-surface
precedent of #25831).
## Skills diff readings (lines; tokens = ceil(bytes/4) per
`check-skills-token-ratchet`)
| file | lines before → after | tokens before → after |
|---|---|---|
| `skills/objectui/rules/protocol.md` | 377 → 375 | 4368 → 4365 |
| `skills/objectui/guides/schema-expressions.md` | 646 → 642 | 6571 →
6571 |
| whole package, sum of all `SKILL.md` | 4525 → 4525 | — |
The guide's net content is paid by deleting one redundant `hidden`
template example (the "Data-dependent" pattern duplicated the syntax
block above it); the token ratchet is green at the ceiling.
## 维护者速读(草稿)
### 改了什么
objectui 节点上的 `visibleOn` / `hiddenOn` / `disabledOn` 三个拼法退役:类型面变为
`never`,Zod 镜像按名拒绝并指向 `visibleWhen` / `hidden` /
`disabled`(同一谓词、同一极性,只改键名,值不变);渲染器只读存活的三个键;SDUI 解析器对 TSX
树同样按名报告;技能包与文档改教存活拼法;`objectui validate` 直接打印拒绝原因。
### 为什么改
规范(ADR-0089)在每一层只声明一个条件可见谓词 `visibleWhen`,从未声明 `*On` 后缀;objectui
自造的三个别名与规范键被同一段代码、同一极性求值,只增加了方言数,没有增加能力。保留别名意味着同一件事有两种写法、两份文档和两组测试要维护。
### 风险与代价(含回滚)
-
风险:任何仍写这三个键的页面/视图/组件文档会在校验时被按名拒绝(有修法提示),渲染时该键被忽略。仓内示例、fixture、技能示例均无命中;文档与技能中的示例已同
PR 改写。
- 代价:四个 `@object-ui/*` 包发版(三个 minor、一个 patch),changeset 已标
BREAKING;无迁移脚本(objectui 面不进 `packages/spec` 的 ADR-0087 账本,沿 #25831 的处置)。
- 回滚:整体 revert 本 PR 即可,无数据迁移、无生成物需要回退(`sdui.manifest.json`
字节不变,仅源码摘要记录重录)。
### 席位意见
(留空)
### 你要做的
1. 确认接受「立即退役、无别名窗口」(派发令如此要求)与 `Metadata-protocol: narrowed` 的判定(认领写的是「按
diff 判定,预期 none」,实测为 narrowed:可写面上的键被 tombstone)。
2. 确认 Acceptance note 1:布尔 `visible` 按规范继续保留在 `BaseSchema` 上(ADR-0089 D4
明确不在范围),派发令中「收敛为 visibleWhen + hidden」的字面读法未照办。
3. 按席位复核后合入;本 PR 为 Tier H,等人批。
## Acceptance notes
1. **`visible` stays.** The order reads "collapse to `visibleWhen` +
`hidden`". `visible` is spec-declared on action nodes, app navigation
entries, tab rows, `record:alert`, bulk actions, action params and
settings, and ADR-0089 D4 keeps boolean `visible` out of scope; the
premise comment says "keep boolean `visible` only where the spec
declares it". Removing the renderer leg would leave a declared key
unevaluated (声明即强制) and would breach the 38-file reader surface. So the
chain collapses from five legs to three: `visibleWhen` / `visible` /
`hidden`. Flagged for the seat to confirm.
2. **`Metadata-protocol: narrowed`, not `none`.** The claim expected
`none` ("ui types only"); the diff tombstones three keys on objectui's
authorable node face, which is "a key removed or tombstoned" by ruling
A's definition, and the level gate pairs it with the claim's `no
(narrowing)` arm. Both lines are on the changeset; the ADR-0087 gate
accepts the disposition. The seat may amend the claim.
3. **`objectui check` names nothing by itself.** The order says
`validate` / `check` refuse the three by name. `validate` does (measured
below). `check` is an advisory sweep that, by the objectui#11007 triage
ruling, does not parse a file its structural arm recognised; a stale
file is reported "recognised but not validated" and sent to `validate`.
Dropping the three markers instead would let a leaf file carrying only a
retired key and an unregistered `type` fall out of the sweep
unmentioned, which is the silence the `body` precedent refused. Left as
the ruling has it; the seat may rule otherwise.
4. **Out of scope, found while reading:** the table-slot refusals in
`zod/objectql.zod.ts` (`tableKeyRefusal('hiddenOn')` and siblings at
lines 1171–1199) still prescribe "belongs on the object-view node
itself", which now points at a tombstoned spelling. Not this card's
keys; for the seat to file. `responsive.hiddenOn`, `FormField.visibleOn`
(view-level) and the `suggestions.zod.ts` examples are untouched as the
order states.
## Deviations
1. **File surface, docs:** the claim lists `guide/expressions.md`,
`api/schema-reference.md`, `guide/schema-playground.md`. Three more
files under `ui/content/docs` taught the retired spellings as live node
keys (`guide/schema-rendering.md` ×11, `guide/metadata-diagnostics.md`
×3 node-level mentions, `utilities/runner.mdx` ×1) and are fixed in
place under the bounded in-place-fix exemption (same defect class,
mechanical rename, same gate family, no new verification surface). The
seat is asked to amend the claim's file surface.
2. **Ablation docblock corrected once:** the new react pin's
reverse-verification paragraph first named the `VISIBILITY_*_KEYS` lists
as the ablation site; the first ablation stayed green because the legs
are hand-written `if` blocks and the lists only drive diagnostics. The
paragraph now names the leg; the second ablation (one restored leg) went
red on exactly the predicted case. Both runs are in the report.
## Verification
- `objectui validate` on `{ "type": "text", "content": "Open",
"visibleOn": "data.ok" }` → exit 1, one error at `visibleOn`, code
`invalid_type`, message "Unrecognized key(s) on this node: `visibleOn`.
Did you mean `visibleOn` → `visibleWhen`? …Rename the key; the value is
unchanged."; the same node spelled `visibleWhen` → exit 0.
- Reverse verification (TypeScript face): `visibleOn: 'data.ok'` pasted
into the typed node literal of the new types test → `tsc -p
tsconfig.test.json` red, TS2322 "Type 'string' is not assignable to type
'undefined'" at line 78; restored via `git checkout HEAD -- FILE` →
green.
- Ablation (`scripts/ablation-replace.mjs`, mutation landed and
restored, blob == HEAD): restoring a `visibleOn` leg after the `visible`
leg in `SchemaRenderer.tsx` →
`SchemaRenderer.visibilityDialectsRetired.test.tsx` 1 failed | 6 passed,
the failing case being "`visibleOn: "false"` is not a SHOW leg"; the
earlier list-only mutation stayed 7 passed (recorded, see deviation 2).
- Type-check: `@object-ui/types`, `core`, `sdui-parser`, `components`,
`react`, `app-shell`, `cli`, `plugin-chatbot` — all exit 0 after `pnpm
--filter '@object-ui/cli...' --filter '@object-ui/app-shell...' build`.
- Tests: `cd ui && pnpm exec vitest run packages/types/
packages/sdui-parser/ packages/react/ packages/components/
packages/plugin-chatbot/ --maxWorkers=2` (under the verify lock, 19m58s)
→ first run 1 failed | 1050 passed
(`static-table-narrow-surface.test.ts` pinned the table mirror's exact
tombstone set, which now inherits the three node-face tombstones;
re-pointed in 6f044d4, that file alone re-run: 39 passed); `…
packages/app-shell/ --maxWorkers=2` → Test Files 1735 passed | 1 skipped
(1736), Tests 15960 passed | 9 skipped; `pnpm --filter @object-ui/core
test` → 211 files passed; `pnpm --filter @object-ui/cli test` → 30 files
passed; the 13 directly touched/new pins run alone → 13 files, 267 tests
passed. (Per-package `pnpm --filter @object-ui/types test` fails with
`spawn ENOENT` from the repo root: vitest lives in
`ui/node_modules/.bin`, so the ui suites are run from `ui/`.)
- Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 68 families at the final head; every
command run from the worktree with its exit captured before any pipe;
`--ran` reconciliation: 68 derived, 68 run, 0 UNRUN. 66 exit 0. `pnpm
check:type-check-debt` → re-run under the lock after the suites (exit 0,
held the lock 131s). `pnpm check:dual-build-cjs-loads` → exit 99 (never
acquired the lock behind the 74-minute app-shell run; a full-build gate
CI runs on the PR, not re-run here).
- Dogfood battery (final head, `(narrowing)` arm): head 6f044d4, after
`pnpm --filter '@objectstack/dogfood^...' build` (exit 0); `pnpm
--filter @objectstack/dogfood test` under the lock → VERDICT
command-exit 0 · held the lock 973s (16m13s) · Test Files 297 passed | 3
skipped (300) · Tests 2527 passed | 18 skipped (2545); no failure.
- `check-platform-checklist --changed-from origin/main`: 0 anchored
files, nothing judged. `check-skills-token-ratchet`,
`check-adr-0087-registration`, `check-changeset-no-major`,
`check-empty-changeset`, `check:doc-authoring`,
`check:pm-skill-id-lint`, `check-sdui-manifest` all green on the
committed tree.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01E5XcbmSeZTDGm5zCYkC9XV
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 77a52cf commit e843b5b
61 files changed
Lines changed: 870 additions & 443 deletions
File tree
- .changeset
- scripts/sdui-manifest.sources
- skills/objectui
- guides
- rules
- ui
- content/docs
- api
- guide
- utilities
- packages
- app-shell/src/chrome
- cli/src/commands
- components/src/renderers
- __tests__
- action
- __tests__
- disclosure
- form
- core/src
- evaluator
- utils
- plugin-chatbot/src
- react/src
- __tests__
- utils
- sdui-parser/src
- __tests__
- types/src
- __tests__
- zod
- scripts
- __tests__
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| 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 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
236 | 236 | | |
237 | 237 | | |
238 | 238 | | |
239 | | - | |
| 239 | + | |
| 240 | + | |
240 | 241 | | |
241 | 242 | | |
242 | 243 | | |
| |||
250 | 251 | | |
251 | 252 | | |
252 | 253 | | |
253 | | - | |
| 254 | + | |
254 | 255 | | |
255 | 256 | | |
256 | | - | |
| 257 | + | |
| 258 | + | |
257 | 259 | | |
258 | 260 | | |
259 | 261 | | |
| |||
269 | 271 | | |
270 | 272 | | |
271 | 273 | | |
272 | | - | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | 274 | | |
279 | 275 | | |
280 | 276 | | |
| |||
290 | 286 | | |
291 | 287 | | |
292 | 288 | | |
293 | | - | |
| 289 | + | |
294 | 290 | | |
295 | 291 | | |
296 | 292 | | |
297 | 293 | | |
298 | 294 | | |
299 | | - | |
| 295 | + | |
300 | 296 | | |
301 | 297 | | |
302 | 298 | | |
| |||
641 | 637 | | |
642 | 638 | | |
643 | 639 | | |
644 | | - | |
| 640 | + | |
645 | 641 | | |
646 | 642 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
17 | | - | |
| 16 | + | |
| 17 | + | |
18 | 18 | | |
19 | | - | |
20 | | - | |
21 | | - | |
| 19 | + | |
22 | 20 | | |
23 | 21 | | |
24 | 22 | | |
25 | 23 | | |
26 | | - | |
| 24 | + | |
27 | 25 | | |
28 | 26 | | |
29 | 27 | | |
| |||
111 | 109 | | |
112 | 110 | | |
113 | 111 | | |
114 | | - | |
115 | | - | |
116 | | - | |
| 112 | + | |
| 113 | + | |
117 | 114 | | |
118 | 115 | | |
119 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | | - | |
74 | | - | |
75 | | - | |
| 73 | + | |
| 74 | + | |
76 | 75 | | |
77 | 76 | | |
78 | 77 | | |
| |||
96 | 95 | | |
97 | 96 | | |
98 | 97 | | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
103 | 102 | | |
104 | | - | |
| 103 | + | |
105 | 104 | | |
106 | 105 | | |
107 | 106 | | |
| |||
1439 | 1438 | | |
1440 | 1439 | | |
1441 | 1440 | | |
1442 | | - | |
| 1441 | + | |
1443 | 1442 | | |
1444 | 1443 | | |
0 commit comments