Skip to content

Commit 3e4fa2c

Browse files
feat(types,components)!: retire four zero-read or third-spelling keys, mirror two chatbot keys, file eighteen runtime slots by name (objectui#6152, round 4) (#11285)
Refs #6152 Clause-②: yes (narrowing). The two mirrors widen `@object-ui/types/zod` and the strict authoring face to keys the TypeScript face already invited and the renderers read (`requestBody`, `floatingConfig`). The four retirements (`label.content`, `report.chartConfig`, `report.reportType`, `detail-view.autoDiscoverRelated`) narrow both faces at once, under the startup no-gradualism rule. It is priced in `.changeset/6152-unmirrored-round4.md` as `minor`, with the break stated. Round 4 of objectui#6152, dispatched under claim `5919877490` (the `domain:devx` seat 2, session `session_01TdiauJaVCHuj45EzZGUxHh`, on the maintainer's direct order). The rulings are the seat review `5914490915`: Q1 B, Q2 A, Q3 B. ⛔ This is a draft from a dispatched dev: do not mark it ready and do not enable auto-merge. The card stays open, because `ObjectGridSchema`, the spec-derived pairs and three `DataTableSchema` keys (below) are not this round's. ## What changed 1. **Q1 B: `LabelSchema.content` is retired.** It is `?: never` on `form.ts` and a `retirementTombstone` on `form.zod.ts` that names the kept spellings `text` and `label`. The `label` renderer drops its third read limb (`schema.text || schema.label`). Re-measured: 0 documents author it (JSON, Markdown JSON fences and typed literals); its only author was a test in `form-renderers.test.tsx`, which now pins the refusal. Which of `text` / `label` is canonical is not decided here. 2. **Q2 A: `DetailViewSchema` `activities`, `comments`, `history` and `recordNavigation` go to `RuntimeOnlyDeclared` by name.** Each has a row with its reason on `RuntimeOnlyNamedAllowList`, in round 3's shape. They carry host-fetched runtime data, and `recordNavigation.onNavigate` is a required function. 3. **Q3 B, under objectui#7654 ruling B: `displayMode` keeps its TypeScript-only refusal.** It gets no zod arm, because stored designer documents carry `displayMode: 'floating'` (pinned by `chatbot-display-mode-retired.test.ts`). The ledger entries no longer call the mirror half "owed"; the key stays listed by decision. Separately, after a reader census for each: - `ChatbotSchema.requestBody` is mirrored through the shared pick. All three chatbot registrations read it (`body: schema.requestBody`). - `ChatbotFloatingSchema.floatingConfig` is mirrored through a module-private restatement of `FloatingChatbotConfig`. That restatement judges the six members `FloatingChatbot` destructures, and carries the `triggerIcon` tombstone's runtime half that the objectui#7654 tripwire asked for. 4. **The three zero-read candidates are retired on both faces.** They are `ReportComponentSchema.chartConfig`, `ReportComponentSchema.reportType` and `DetailViewSchema.autoDiscoverRelated`, each `?: never` plus a `retirementTombstone`. `reportType`'s one in-code producer, `specReportToPresentation` in `spec-report.ts`, no longer writes it, and `LegacyReportPresentationLike` no longer declares it. 5. **`DataTableSchema`: 14 of 17 keys go to `RuntimeOnlyDeclared` by name.** They are produced only in code, by `ObjectGrid`'s in-code `data-table` node or `RelatedList`'s, and authored by no document. Three keys fit none of the classes, so the round stopped at them (see "Stopped" below). 6. **The pagination corpus fix, carried from round 3.** `components-basic-pagination/with-item-count.json` no longer authors `pageSize` / `totalItems`, which neither face declares and nothing reads. The plaintext interface block on `content/docs/components/basic/pagination.mdx` stops listing them, and its section is retitled from "With Page Size" to "On a Later Page". 7. **Changesets.** One new: `.changeset/6152-unmirrored-round4.md` (`@object-ui/types` minor, `@object-ui/components` minor, with the break stated). Four dated, append-only corrections were added, each 2 lines with frontmatter unchanged: `6639-objectgrid-title-mirrored.md` (the stale "97 + 1 + 23" sentence), `7654-floating-chatbot-trigger-icon-tombstone.md`, `7655-chatbot-registration-authoring-faces.md` and `9447-detail-view-handler-key-refusal.md`. Every other pending changeset was re-read after the merges, including the 8 that landed since the base, and none is made false by this round. ## Ledger totals, before and after These are read by the file's own pins (`objectui#7279` derives every figure) and re-counted with the TypeScript parser on the final head. | ledger | before (`origin/main` `e420df3`) | after (`2cc4ab9`) | | --- | --- | --- | | `UnmirroredDeclared` | 9 entries / 44 keys: 3 / 14 spec-derived, 6 / 30 local | **6 / 20**: 3 / 14 spec-derived, 3 / 6 local | | `RuntimeOnlyDeclared` | 4 / 9 | **4 / 27** | | `RuntimeOnlyNamedAllowList` | 1 entry / 2 rows | 3 / 20 | | cross-ledger | 2 of the 4 are in `UnmirroredDeclared`; union 11 = 9 + 2 | **1 of the 4**; union **9** = 6 + 3 | | `KnownDrift` | 49 / 86 | 49 / 86, unchanged. This round does not edit its total line; PR #11269's 87 to 86 edit is kept as merged. | | `WiderThanDeclared`, `MirroredUndeclared` | 3 / 3, 2 / 2 | unchanged | The 24 keys that left `UnmirroredDeclared` moved by three routes, which must not be added up as one repair: 2 were mirrored, 4 were retired, and 18 were reclassified by name. The reclassification is one move seen from both ledgers: it is not new debt, and it mirrors nothing. ## Per-key table | pair · key | measured (type-checker read census over 5548 sources; authored census over tracked JSON, Markdown JSON fences and `type` literals) | route | | --- | --- | --- | | `label` · `content` | 1 read (the third limb in `label.tsx`), 0 documents (1 test) | retired on both faces; the read is dropped | | `report` · `chartConfig` | 0 typed reads. The untyped `widget?.chartConfig` hits are plugin-dashboard's `DatasetWidget` (`widget: any`, a dashboard widget), which plugin-report never imports. 0 documents | retired on both faces | | `report` · `reportType` | 0 reads; one in-code producer (`specReportToPresentation`); 0 documents | retired on both faces; the producer write is removed | | `detail-view` · `autoDiscoverRelated` | 0 reads (typed or untyped), 0 documents | retired on both faces | | `chatbot` · `requestBody` | 3 reads (all three chatbot registrations) | mirrored (shared pick) | | `chatbot-floating` · `floatingConfig` | 1 read (`floatingConfig={schema.floatingConfig}`); 6 of 7 `FloatingChatbotConfig` members read, and `triggerIcon` 0 | mirrored, with a `FloatingChatbotConfig` restatement | | `chatbot`, `chatbot-floating` · `displayMode` | 0 reads; stored documents carry it | unchanged by ruling (TypeScript-only refusal) | | `detail-view` · `activities` (7 reads), `comments` (4), `history` (7) | host-fetched rows; 0 documents | `RuntimeOnlyDeclared` by name | | `detail-view` · `recordNavigation` | 11 reads; its value carries a required function | `RuntimeOnlyDeclared` by name | | `data-table` · `disableInnerScroll`, `manualPagination`, `manualSearch`, `manualSorting`, `page`, `rowActionDefs`, `rowClassName`, `rowCount`, `rowStyle`, `search`, `selectionResetKey`, `showAddRow`, `showSelectionCount`, `sort` | read by `data-table`; produced only in code (`ObjectGrid`, `RelatedList`); 0 docs and 0 catalog documents | `RuntimeOnlyDeclared` by name; the reasons are on the allow-list | | `data-table` · `editable`, `singleClickEdit` | read; produced in code by `ObjectGrid`; 0 documents, but `data-table.mdx` lists both and teaches `editable: true` | **stopped**, ruling needed | | `data-table` · `selectionStyle` | read; 0 producers and 0 documents (0 hits in objectstack too) | **stopped**, ruling needed | ## Runtime probe for the three zero-read retirements AGENTS.md requires more than a source census, because leftover keys reach a renderer as spread props. So the probe used the real `SchemaRenderer` and the real registry, and varied only the key. It was a one-off: the files were deleted afterwards and `git diff HEAD` is empty. - `report`: the DOM is identical with and without `chartConfig` plus `reportType` (797 = 797 characters, byte-equal). Lit control: changing `title` changes the DOM (805). - `detail-view`: the DOM is identical with and without `autoDiscoverRelated: true`, after normalising React's `useId` tokens. The only raw difference was `radix-_r_5_` against `radix-_r_d_`. The data-source and `fetch` call log is identical: `getObjectSchema(account)` and two `security/explain` fetches. Lit control: changing `title` changes the DOM (5943 against 5951). ## Ablations The predictions were written at `4c272dc` before any run, and every leg was restored with the blob equal to `HEAD` and `git diff HEAD` empty. - **A1:** plant a `LabelSchema` literal carrying `content` into `label.tsx`. Components `tsc --noEmit` exits 2 with exactly one TS2322 there (`'string' is not assignable to type 'undefined'`), as predicted. This red direction also shows the consumer read the rebuilt `.d.ts`. - **A2:** restore the four `zod/*.zod.ts` files to base `f61dab1`. `unmirrored-declared-round4-6152.test.ts` reads `27 failed | 6 passed (33)`, exactly as predicted, and `tsc -p tsconfig.test.json` exits 2 with its only error in the ledger reconciliation of `zod-mirror-parity.test.ts`. - **A3:** rename the allow-list row `rowCount` to `rowCountRenamed`. `tsc -p tsconfig.test.json` exits 2 with exactly two TS2344, at the two allow-list pins, as predicted. ## Verification on the final head `2cc4ab9` This round resumed after two container restarts, so every run below was redone on `2cc4ab9`. That head carries `origin/main` `e420df3`, merged twice (never rebased): once through PR #11275, and before that through PRs #11267, #11268, #11269, #11271, #11273 and #11274. Each run went through the shared verify lock with at most 2 workers. - `@object-ui/types`: `type-check` (the `--noEmit`, `tsconfig.examples.json` and `tsconfig.test.json` legs) exits 0; `vitest run packages/types/` gives 299 files and 7498 tests passed; `build` exits 0 (138 emitted files verified). - Consumers, from the type-checker census: `type-check` exits 0 with 0 TS errors for `components`, `plugin-report`, `plugin-detail` and `plugin-chatbot`. `vitest run packages/plugin-report/ packages/plugin-chatbot/` plus `form-renderers.test.tsx` gives 78 files, 827 passed and 7 skipped. All 228 `plugin-detail` test files, run in two halves, give 227 files passed plus 1 skipped, and 2264 tests passed plus 8 skipped. - Zod-face consumers: `vitest run examples/schema-catalog/ packages/cli/` plus the 17 app-shell files that import `@object-ui/types/zod` or sit in `metadata-admin/previews/__tests__` give 77 files and 2741 tests passed. - Gates, all exit 0: `check:changeset-claims`, `check:pending-changeset-literals`, `check-changeset-presence` (16 source files of 2 released packages, 1 changeset), `check-changeset-no-major`, `check-changeset-fixed`, `check-changeset-overwrite` (report-only; its 4 findings are the 4 dated appends above), `check:control-bytes` (9717 files), `check:doc-fences`, `check:doc-snippets` (697 of 697 blocks judged, 0 failed), `check:doc-examples`, `check:doc-types`, `check:doc-example-ids`, `check:doc-example-readers`, `check:skill-examples`, `check:handler-key-reads`, `check:component-surface-parity` (report-only), `check:designer-field-key-parity`, `check:element-data-source-declaration`, `check:new-line-citations` (0 new), `check:prompt-keys`, `check:readme-exports`, `check:spec-symbols`, `check:test-path-roots`, `check:unreferenced-sources` and `check-type-check-coverage`. `doc-snippets` and `doc-examples` ran after the scoped build their own `--build-filter` names (35 turbo tasks, all successful). - Lint, narrowed: `eslint --no-inline-config --format json` over the 16 lintable changed files gives 0 errors. All 16 were judged and 0 were ignored, a population read from eslint's own output. The 39 warnings are pre-existing `no-explicit-any`, and the diff adds no explicit `any`. `eslint.config.js` declares no `parserOptions.project` or `projectService`, and no custom rule in `eslint-rules/` reads the disk, so this diff cannot move any untouched file's verdict. The repo-wide `pnpm lint` is CI's. - Governed surface: `check-governed-queue-guard.mjs --test` over the 23 paths reports NOT GOVERNED. - NOT MEASURED: - `check:sdui-registration-pins`: it needs a console build, and this diff changes no registration. - The full `pnpm test` farm and repo-wide lint: CI's. - `plugin-grid`: its code and tests are untouched. The 14 reclassified keys moved between two test ledgers and no declaration changed. ## Stopped (ruling needed; reported in the card report with options) - `DataTableSchema.editable` and `singleClickEdit`. `data-table` reads both and `ObjectGrid` sets both in code, while no document authors them. But `content/docs/components/complex/data-table.mdx` lists both in its interface block and teaches `editable: true`. Filing them runtime-only would contradict that page. Mirroring them would rest on no authored document, and, from the source, an authored `editable: true` stages cell edits locally and persists nothing without the `onRowSave` / `onCellChange` function slots. - `DataTableSchema.selectionStyle`. `data-table` reads it (`'always'` or `'hover'`), and nothing authors or produces it in either repository. - Noted, not narrowed: `ChatbotSchema.floatingConfig` has 0 reads on the `chatbot` node (only `chatbot-floating` reads it), which makes it an ADR-0049 narrowing candidate. The `chatbot` half of `floating-chatbot-trigger-icon-retired.test.ts` pins its absence as a tripwire. ## Parallel discipline PR #11269 and PR #11273 edited `zod-mirror-parity.test.ts` in disjoint hunks: the `KnownDrift` total line, the Kanban entry and one `EXCLUSIONS` row. Both merges were clean. This round's ledger edits stay in the `UnmirroredDeclared` / `RuntimeOnlyDeclared` / `RuntimeOnlyNamedAllowList` blocks, their prose totals and its own pairs' entries. Every prose total was reconciled to the measured count above. The diff does not touch `zod/objectql.zod.ts`, `zod/index.zod.ts`, `zod/nested-component-walk.ts`, `strict-authoring-face.ts`, `zod/README.md`, `field-types.ts`, the `DetailViewField` member, or `data-table.tsx` (read only). ## Acceptance notes - 23 files, under the ~25-file size guard, so no pair was cut. - Every pending changeset this round made false carries a dated append. The ones it leaves true were re-read: `7654-chatbot-display-mode-tombstone.md`, `6150-…`, `7804-…`, `6175-…`, `7722-…`, `7947-…` and `8072-…`. Session: `https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh` --- _Generated by [Claude Code](https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 58da8ae commit 3e4fa2c

23 files changed

Lines changed: 754 additions & 226 deletions
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
'@object-ui/types': minor
3+
'@object-ui/components': minor
4+
---
5+
6+
feat(types): four declared keys nothing honoured are retired on both faces, and two chatbot keys gain their zod mirror (objectui#6152, round 4)
7+
8+
**Retired (breaking).** Each key below was declared on a published TypeScript type in
9+
`@object-ui/types` and unknown to its zod mirror in `@object-ui/types/zod`. None of them is
10+
honoured, so each is retired at once, with no alias window:
11+
12+
- `label`: `content`, a third spelling of the label text beside `text` and `label`. The `label`
13+
renderer in `@object-ui/components` read it last (`text`, then `label`, then `content`) and no
14+
longer reads it, so a node that carries only `content` renders no text. No document in this
15+
repository authored it. Write `text` (or `label`).
16+
- `report`: `chartConfig` and `reportType`. Nothing read either key off a report, so an authored
17+
value configured nothing. `specReportToPresentation` no longer writes `reportType` onto the
18+
presentation it returns, and `LegacyReportPresentationLike` no longer declares it.
19+
- `detail-view`: `autoDiscoverRelated`. Nothing read it: `detail-view` does not discover related
20+
lists from reference fields. Author a `record:related_list` block for each related list.
21+
22+
For each retired key:
23+
24+
- the TypeScript member is now `?: never`, so writing it is a `tsc` error;
25+
- the zod mirror refuses it by name at the key, on the tolerant validator (`AnyComponentSchema`,
26+
`safeValidateSchema`) and on the strict authoring face (`StrictAnyComponentSchema`) alike. The
27+
tolerant validator used to keep the value without examining it.
28+
29+
Delete the key from any document or literal that carries it.
30+
31+
**Mirrored.** Two chatbot keys the published types declare, and the renderers read, gain their
32+
zod arm:
33+
34+
- `chatbot`: `requestBody`, the chat API's extra body params. All three chatbot nodes now share
35+
one `requestBody` arm. The strict authoring face used to refuse `requestBody` on a `chatbot`
36+
node, although the type invites it and the retirement of `body` points authors at it.
37+
- `chatbot-floating`: `floatingConfig`, judged member by member (`position`, `defaultOpen`,
38+
`panelWidth`, `panelHeight`, `title`, `triggerSize`). Its retired `triggerIcon` member is now
39+
refused at runtime too, on this node. On a `chatbot` node `floatingConfig` stays unvalidated,
40+
because the `chatbot` renderer never reads it.
41+
42+
A wrong-typed value at either key, for example a string `requestBody` or a `floatingConfig`
43+
`position` of `'top-left'`, is now refused at its path, where it used to be kept unexamined
44+
(breaking for invalid documents).
45+
46+
`@object-ui/types` and `@object-ui/components` are in the fixed release group, so this ships as a
47+
minor bump, per the repository's version policy.
48+
49+
`displayMode` on the two chatbot types is unchanged: its refusal stays TypeScript-only, so stored
50+
designer documents that carry `displayMode: 'floating'` parse exactly as before.

‎.changeset/6639-objectgrid-title-mirrored.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ admitting any `title` unexamined, and it now enforces the declared `string`.
1515
`zod-mirror-parity.test.ts`'s `UnmirroredDeclared` ledger records the key as
1616
worked off — the ledger's first shrink by repair (97 + 1 mirrored + 23
1717
reclassified is what the seeded "121" now means).
18+
19+
**Correction, 2026-09-30 (objectui#6152, round 4).** The last sentence above says "97 + 1 mirrored + 23 reclassified" is what the seeded "121" now means. That was a reading when this change was written, and it no longer is: later changes mirrored, retired and reclassified further keys, and the survivor count it names went stale before objectui#6152 round 3. No live decomposition of "121" is kept anywhere, because the ledgers record no per-key provenance. The dated readings, and the live total, are in `zod-mirror-parity.test.ts`, whose pins derive them. The mirroring of `title` this entry describes is unaffected.

‎.changeset/7654-floating-chatbot-trigger-icon-tombstone.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,5 @@ That file also pins the runtime half as a **tripwire**: it asserts that a node c
6868
`FloatingChatbotConfigSchema`, it goes red — the intended signal that whoever lands the
6969
mirror must add the `retirementTombstone()` half at the same time and flip the control
7070
rather than delete it into a vacuum.
71+
72+
**Correction, 2026-09-30 (objectui#6152, round 4).** The sections above say `FloatingChatbotConfig` has no zod mirror, so the `triggerIcon` refusal is type-level only and the runtime face does not change. That was true when this change was written, and it is now true on a `chatbot` node only. objectui#6152 round 4 minted the mirror on the `chatbot-floating` node, the one whose renderer reads `floatingConfig`, together with the `retirementTombstone()` half this entry asked for. So a `chatbot-floating` node that carries `floatingConfig.triggerIcon` is now refused at that path. The tripwire test was flipped for that node, not deleted.

‎.changeset/7655-chatbot-registration-authoring-faces.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,5 @@ registration reads it, so it leaves `ChatbotSharedKey`, and `ChatbotSchema` decl
116116
instead as a `?: never` member that the other two faces pick by name, refused by name on
117117
the zod twins. The "twenty keys" above is kept as the reading of this change; the
118118
objectui#5605 retirement entry states what the three faces declare now.
119+
120+
**Correction, 2026-09-30 (objectui#6152, round 4).** The "Zod twins" section above says the floating twin leaves `floatingConfig` unmirrored because no `FloatingChatbotConfig` mirror exists. That was true when this change was written, and it no longer is: objectui#6152 round 4 minted that mirror and declared `floatingConfig` on the `chatbot-floating` twin, judged member by member. The same round declared `requestBody` on `ChatbotSchema`'s twin, so all three chatbot twins now share one `requestBody` arm. `displayMode` stays unmirrored on both twins, as this entry says.

‎.changeset/9447-detail-view-handler-key-refusal.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,5 @@ behaviour as a node type (`{ "type": "toast", ... }`, an `action:button` node).
4747
different path with a different signature (`(recordId) => void`), which stays
4848
authorable on both faces; and `onTabChange`, whose disposition is still open on
4949
the handler-key parent card and which this change deliberately does not touch.
50+
51+
**Correction, 2026-09-30 (objectui#6152, round 4).** The last paragraph above says the nested `recordNavigation.onNavigate` "stays authorable on both faces". It was never authorable in a JSON document: its value is a required function, and the zod mirror has never declared `recordNavigation`. objectui#6152 round 4 recorded `recordNavigation` as a runtime slot a host sets in code. No published face changed with that, and the refusals this entry describes are unaffected.

‎content/docs/components/basic/pagination.mdx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@ The Pagination component allows users to navigate through pages of data.
99

1010
<SchemaExample id="components-basic-pagination/basic-pagination" />
1111

12-
## With Page Size
12+
## On a Later Page
1313

1414
<SchemaExample id="components-basic-pagination/with-item-count" />
1515

16+
`pagination` has no page-size or item-count keys: the page state it reads is
17+
`currentPage` and `totalPages`.
18+
1619
## Schema
1720

1821
```plaintext
1922
interface PaginationSchema {
2023
type: 'pagination';
2124
currentPage: number; // Current page (1-based)
2225
totalPages: number; // Total number of pages
23-
pageSize?: number; // Items per page
24-
totalItems?: number; // Total number of items
2526
2627
// Events
2728
// RUNTIME SLOT (objectui#6124): a React host supplies it; JSON refuses it
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
{
22
"type": "pagination",
33
"currentPage": 3,
4-
"totalPages": 20,
5-
"pageSize": 10,
6-
"totalItems": 200
4+
"totalPages": 20
75
}

‎packages/components/src/__tests__/form-renderers.test.tsx‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,26 @@ describe('Form Renderers - Display Issue Detection', () => {
359359
it('should render label element', () => {
360360
const { container } = renderComponent({
361361
type: 'label',
362-
content: 'Form Label',
362+
text: 'Form Label',
363363
});
364364

365365
const label = container.querySelector('label');
366366
expect(label).toBeTruthy();
367367
expect(label?.textContent).toContain('Form Label');
368368
});
369+
370+
it('no longer reads the retired `content` spelling (objectui#6152)', () => {
371+
// `content` was the renderer's third read, after `text` and `label`. Both faces of
372+
// `@object-ui/types` retire it, so a node carrying only `content` renders no text.
373+
const { container } = renderComponent({
374+
type: 'label',
375+
content: 'Retired Spelling',
376+
});
377+
378+
const label = container.querySelector('label');
379+
expect(label).toBeTruthy();
380+
expect(label?.textContent ?? '').not.toContain('Retired Spelling');
381+
});
369382
});
370383

371384
describe('Field locators (ADR-0054 C4)', () => {

‎packages/components/src/renderers/form/label.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ ComponentRegistry.register('label',
2727
// Apply designer props
2828
{...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType, style }}
2929
>
30-
{schema.text || schema.label || schema.content}
30+
{/* `text`, then `label`. A third spelling, `content`, is retired on both
31+
faces of `@object-ui/types` and is no longer read (objectui#6152). */}
32+
{schema.text || schema.label}
3133
</Label>
3234
);
3335
},

‎packages/types/src/__tests__/chatbot-registration-authoring-faces-7655.test.ts‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@
4747
* `?: never` tombstone on both faces now, the designer control and the
4848
* `defaultProps` seed in the `chatbot-floating` registration are gone, and the
4949
* key stays UNMIRRORED on both twins. The runtime pin below still asserts it
50-
* parses green with any value, as a tripwire for the moment objectui#6152
51-
* mints an arm; the tombstone's own pins are in
52-
* `chatbot-display-mode-retired.test.ts`.
50+
* parses green with any value, as a tripwire; objectui#6152 round 4 kept the
51+
* refusal TypeScript-only under that ruling, so no arm is owed. The
52+
* tombstone's own pins are in `chatbot-display-mode-retired.test.ts`.
5353
*
5454
* ## The census counts NAMED reads; the floating registration has a second channel
5555
*
@@ -376,8 +376,9 @@ describe('`ChatbotEnhancedSchema` (zod) validates what the face declares', () =>
376376
});
377377

378378
it('mirrors `requestBody` under the key the renderer reads, and refuses a non-object', () => {
379-
// `ChatbotSchema`'s twin mirrors this under `body`, colliding with the base
380-
// children slot; the two new twins do not copy that collision.
379+
// `ChatbotSchema`'s twin used to mirror this under `body`, colliding with the
380+
// base children slot; objectui#8572 retired that arm, and since objectui#6152
381+
// round 4 all three twins share one `requestBody` arm through the pick.
381382
expect(ChatbotEnhancedZod.shape.requestBody).toBeDefined();
382383
const result = ChatbotEnhancedZod.safeParse({ ...node, requestBody: 'tenant=acme' });
383384
expect(result.success).toBe(false);
@@ -395,7 +396,7 @@ describe('`ChatbotEnhancedSchema` (zod) validates what the face declares', () =>
395396
});
396397
});
397398

398-
describe('`ChatbotFloatingSchema` (zod) validates what the face declares, and leaves the two shared floating keys unmirrored', () => {
399+
describe('`ChatbotFloatingSchema` (zod) validates what the face declares, and leaves `displayMode` unmirrored', () => {
399400
const node = {
400401
type: 'chatbot-floating',
401402
messages: [{ id: '1', role: 'user', content: 'hi' }],
@@ -419,7 +420,7 @@ describe('`ChatbotFloatingSchema` (zod) validates what the face declares, and le
419420
}
420421
});
421422

422-
it('TRIPWIRE — `displayMode` stays unmirrored here as on `ChatbotSchema`: any value still parses green (retired by objectui#7654; the `retirementTombstone()` half is owed when objectui#6152 mints an arm)', () => {
423+
it('TRIPWIRE — `displayMode` stays unmirrored here as on `ChatbotSchema`: any value still parses green (retired by objectui#7654; the refusal stays TypeScript-only under that ruling, objectui#6152 round 4)', () => {
423424
// objectui#7654 retired the key (maintainer ruling B, 2026-09-05): a
424425
// `?: never` tombstone on both TypeScript faces, designer control and seed
425426
// removed. The RUNTIME face was deliberately left alone — the key has no
@@ -446,11 +447,14 @@ describe('`ChatbotFloatingSchema` (zod) validates what the face declares, and le
446447
expect(ChatbotFloatingZod.safeParse({ ...node, enableMarkdown: 'anything-at-all' }).success).toBe(false);
447448
});
448449

449-
it('`floatingConfig` has no mirror here either — the objectui#6152 axis is not widened into', () => {
450-
expect((ChatbotFloatingZod.shape as Record<string, unknown>).floatingConfig).toBeUndefined();
451-
// Rides through unvalidated, wrong shape and all — byte for byte the
452-
// outcome on `ChatbotSchema`'s twin, which has no arm for it either.
453-
expect(ChatbotFloatingZod.safeParse({ ...node, floatingConfig: { panelHeight: '520px' } }).success).toBe(true);
450+
it('`floatingConfig` is mirrored here since objectui#6152 round 4, and a wrong member value is refused at its path', () => {
451+
// This registration is the one that reads the key; `ChatbotSchema`'s twin,
452+
// whose registration never does, still has no arm for it.
453+
expect((ChatbotFloatingZod.shape as Record<string, unknown>).floatingConfig).toBeDefined();
454+
const wrong = ChatbotFloatingZod.safeParse({ ...node, floatingConfig: { panelHeight: '520px' } });
455+
expect(wrong.success).toBe(false);
456+
expect(wrong.error?.issues.some((i) => i.path.join('.') === 'floatingConfig.panelHeight')).toBe(true);
457+
expect((ChatbotZod.shape as Record<string, unknown>).floatingConfig).toBeUndefined();
454458
});
455459

456460
it('`onClear` / `onError` / `onSend` are refused by name here too', () => {
@@ -465,7 +469,7 @@ describe('`ChatbotFloatingSchema` (zod) validates what the face declares, and le
465469
describe('the census is structural: picked off `ChatbotSchema`, never copied', () => {
466470
const shared: readonly ChatbotSharedKey[] = [
467471
'messages', 'placeholder', 'api', 'conversationId', 'systemPrompt', 'model', 'streamingEnabled',
468-
'headers', 'onError', 'showTimestamp', 'userAvatarUrl', 'userAvatarFallback',
472+
'headers', 'requestBody', 'onError', 'showTimestamp', 'userAvatarUrl', 'userAvatarFallback',
469473
'assistantAvatarUrl', 'assistantAvatarFallback', 'autoResponse', 'autoResponseText',
470474
'autoResponseDelay', 'onSend',
471475
];

0 commit comments

Comments
 (0)