You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(types,components)!: retire data-table selectionStyle and chatbot floatingConfig on both faces, file data-table's inline-edit flags by name (objectui#6152, round 5) (#11320)
Refs #6152
Clause-②: yes (narrowing). `selectionStyle` and the base-face
`floatingConfig` retire on both faces, and `editable` /
`singleClickEdit` leave the authored docs, under the startup
no-gradualism rule. It is priced in the changeset.
Round 5 of objectui#6152, dispatched under claim `5923137359`
(`domain:devx` seat 2, session `session_01TdiauJaVCHuj45EzZGUxHh`, on
the maintainer's direct order). The rulings are the seat review
`5921390451`: its three answers to round 4's open questions. ⛔ This is a
draft from a dispatched dev: do not mark it ready and do not enable
auto-merge. The card stays open: `ObjectGridSchema`'s keys and the
spec-derived pairs (objectui#2231) are not this round's.
## What changed
1. **`DataTableSchema.editable` / `singleClickEdit`: answer 1, B.** Both
keys are filed by name on `RuntimeOnlyNamedAllowList`, each with its
reason, under round 4's class rule: a key a host produces in code and no
document authors (the `showAddRow` precedent). No declaration moved.
`content/docs/components/complex/data-table.mdx` no longer teaches them
on an authored node. The interface block drops them, and the `editable:
true` example becomes an "Inline editing" section. That section says the
capability is host-paired: the table only stages an edit, and
`object-grid` sets both keys on the table it builds and supplies the
save path. It points a document author at `object-grid`. The two
members' doc comments say the same.
2. **`DataTableSchema.selectionStyle`: answer 2, B.** It is retired on
both faces: a `?: never` tombstone on `data-display.ts`, and a
`retirementTombstone()` on `zod/data-display.zod.ts` whose message says
to delete the key and that `selectable` alone turns selection on. The
hover-only checkbox branch in
`packages/components/src/renderers/complex/data-table.tsx` is dropped,
so the `'always'` behaviour is the only one.
3. **Base-face `ChatbotSchema.floatingConfig`: answer 3, A.** It is
retired on the `chatbot` face only: `?: never` on `complex.ts` and a
`retirementTombstone()` on `zod/complex.zod.ts`, whose message names
`type: "chatbot-floating"`.
- **Mechanism, from the measurement:** a base tombstone only, with no
re-declaration. `ChatbotFloatingSchema` does NOT inherit the base
member. Its TS face is `BaseSchema` plus `Pick` of `ChatbotSchema` over
`ChatbotSharedKey` and `maxToolRoundtrips`, plus its own
`floatingConfig` member. Its zod twin is `BaseSchema.extend` with the
shared pick spread and its own `floatingConfig` arm. So the floating
registration's declaration, mirrored in round 4, was already separate on
both faces and is untouched.
- It is a tombstone and not a deletion because `ChatbotSchema` is a
`BaseSchema` carrier, where a deleted member reads as `any` through the
index signature. The discriminator is cited, not restated, so
`tombstone-discriminator-agreement-9684.test.ts` still counts four
statements.
- The chatbot half of `floating-chatbot-trigger-icon-retired.test.ts` is
flipped, not deleted. On a `chatbot` node it now asserts the refusal of
the whole `floatingConfig` key on both faces, a live config included,
with a no-`floatingConfig` control.
`chatbot-registration-authoring-faces-7655.test.ts`'s type pins follow.
4. **Ledger.** `zod-mirror-parity.test.ts`: the `UnmirroredDeclared`,
`RuntimeOnlyDeclared` and `RuntimeOnlyNamedAllowList` blocks, and every
prose total reconciled to the parser count. One non-vacuity leg was
reshaped; see the acceptance notes.
5. **Docs.** `content/docs/plugins/plugin-chatbot.mdx` no longer says
`floatingConfig` type-checks and parses on a `chatbot` node.
6. **Changeset.** `.changeset/6152-unmirrored-round5.md` bumps
`@object-ui/types` and `@object-ui/components` to minor, with the break
stated. Three pending entries that this round makes false get dated,
append-only `**Correction, 2026-10-01**` notes, with frontmatter and
every prior line intact: `6152-unmirrored-round4.md`,
`7654-floating-chatbot-trigger-icon-tombstone.md` and
`7655-chatbot-registration-authoring-faces.md`.
## Per key
| key | node | ruling | route | TS face | zod face | renderer | docs |
|---|---|---|---|---|---|---|---|
| `editable` | `data-table` | B | filed by name, runtime-only
(host-paired) | unchanged (`boolean`), doc comment notes the pairing |
unchanged (not mirrored) | unchanged | removed from the authored
interface block; section rewritten |
| `singleClickEdit` | `data-table` | B | filed by name, runtime-only
(host-paired) | unchanged (`boolean`), doc comment notes the pairing |
unchanged (not mirrored) | unchanged | as above |
| `selectionStyle` | `data-table` | B | retired (ADR-0049) | `?: never`
| `retirementTombstone()` | hover branch dropped | none taught it |
| `floatingConfig` | `chatbot` | A | retired (ADR-0049) | `?: never` |
`retirementTombstone()` | none (never read) | `plugin-chatbot.mdx`
corrected |
| `floatingConfig` | `chatbot-floating` | (kept) | none | unchanged |
unchanged (round 4's arm) | unchanged | unchanged |
## Ledger totals, by TypeScript-parser count of
`zod-mirror-parity.test.ts`
| ledger (entries / keys) | before, base `3d09948` | after, head
`c1b5767` |
|---|---|---|
| `KnownDrift` | 49 / 86 | 49 / 86 |
| `UnmirroredDeclared` | 6 / 20 (3 / 14 spec-derived, 3 / 6 local) | 5 /
16 (3 / 14 spec-derived, 2 / 2 local) |
| `RuntimeOnlyDeclared` | 4 / 27 | 4 / 29 |
| `RuntimeOnlyNamedAllowList` | 3 / 20 | 3 / 22 |
| `WiderThanDeclared` | 3 / 3 | 3 / 3 |
| `MirroredUndeclared` | 2 / 2 | 2 / 2 |
| shared entries / union of the two unmirrored ledgers | 1 of 4 / 9 (6 +
3) | 0 of 4 / 9 (5 + 4) |
⚠️ **The local half is 2 / 2, not the 0 / 0 the dispatch predicted
(hypothesis H1 falsified).** The two keys left are `displayMode` on
`ChatbotSchema` and on `ChatbotFloatingSchema`. Under objectui#7654
maintainer ruling B, kept by round 4's Q3 B, their refusal stays
TypeScript-only: stored designer documents carry `displayMode:
'floating'`. So they stay in `UnmirroredDeclared` by decision, not as
mirroring debt. The ledger prose says so, and the non-vacuity pin "the
LOCAL half read as EMPTY" still holds. After this round,
`UnmirroredDeclared` holds only the spec-derived 3 / 14 (objectui#2231)
and those two decided entries.
## What was measured, before editing (base `3d09948`)
- **Type-checker read and producer census.** The round-4 instrument: the
TS compiler API over every `packages/*/src` and `apps/*/src`, 5585
files.
- `ChatbotSchema.floatingConfig`: 0 reads, 0 producers, 1 test producer
(the tripwire).
- `ChatbotFloatingSchema.floatingConfig`: 1 read (the floating
registration).
- `DataTableSchema.selectionStyle`: 1 read (the `data-table`
destructure) and 0 producers.
- `editable` / `singleClickEdit`: 1 read each (the destructure) and 1
producer each (`ObjectGrid`).
- Lit controls: `ChatbotSchema.messages` 3 reads, `maxHeight` 2,
`DataTableSchema.columns` 2 reads and 2 producers.
- **Authored census in this repository.** 493 tracked JSON files, 354
Markdown JSON fences and 3202 TS/TSX files with a literal `type`.
- `data-table`: `selectionStyle` 0, and `editable` / `singleClickEdit` 1
each, both `ObjectGrid` in code with no document.
- `chatbot`: `floatingConfig` 1, a test.
- Lit controls: `data-table.columns` 71, `selectable` 8,
`chatbot-floating.floatingConfig` 4.
- **objectstack census.** `git grep -i` on a self-named ref of
objectstack `origin/main` (`9b0de7de7`): `selectionStyle`,
`selection_style` and `floatingConfig` 0 hits. The lit control on the
same ref was `singleClickEdit`, with 6 hits, all on the spec's
`ObjectGridProps`, not `data-table`. **There is no named user of
hover-style selection, so the stop condition did not fire.**
- **Runtime probe, a one-off.** The real `SchemaRenderer` and registry,
varying one key. Both files were deleted after each run, leaving `git
status` and `git diff HEAD` empty.
- At base, a selectable `data-table` with `selectionStyle: 'hover'`
differed from unset: 6651 against 6481 characters. The checkbox cell
gained `relative`, and each checkbox was wrapped in a
`transition-opacity opacity-0 group-hover/row:opacity-100` div.
`'always'` was byte-equal to unset, and the `showRowNumbers` control
moved the DOM.
- At head, `'hover'` is byte-equal to unset (6481 = 6481), with no hover
wrapper.
- `chatbot` with against without a full `floatingConfig`: byte-equal at
base and at head (2600 = 2600). The `placeholder` control moved the DOM,
and the same config on `chatbot-floating` drew its title.
## Verification on head `c1b5767`
Every heavy run went through `bash
/home/user/objectstack/scripts/pm/os-verify-lock.sh` with
`OS_VERIFY_LOCK_SLOT=issue-6152`,
`NODE_OPTIONS=--max-old-space-size=4096` and a memory watchdog; the
lowest available memory was 11244 MB.
- **Builds.** `pnpm exec turbo run build` over `check-doc-snippet-types
--build-filter` with `--concurrency=2`: "Tasks: 35 successful, 35
total". `@object-ui/types` reports "dist completeness: 1 package(s)
complete (138 emitted files verified)".
- **Type-checks.** `pnpm --filter X run type-check` exits 0 with 0 TS
errors for `@object-ui/types` (`tsc --noEmit`, `-p
tsconfig.examples.json`, `-p tsconfig.test.json`), `components`,
`plugin-chatbot` and `plugin-grid`. The last three are the packages the
type-checker census named.
- **Tests,** all with `pnpm exec vitest run --maxWorkers=4`:
- `packages/types/`: 306 passed (306), 7701 tests passed;
- `packages/components/` in two runs: 192 passed and 1 skipped (193),
with 1920 tests passed; then 156 passed (156), with 1560 tests passed;
- the consumer set: 309 passed (309), 4939 tests passed. It covers
`plugin-chatbot`, `plugin-grid`, `examples/schema-catalog`,
`packages/cli`, the three app-shell files importing
`@object-ui/types/zod` and
`app-shell/.../metadata-admin/previews/__tests__/`.
- **Gates, each exit 0.**
- Changesets: `check:changeset-claims`, report-only, with 47 pending
entries naming a touched file; three were re-read and corrected as
above. Also `check:pending-changeset-literals`,
`check-changeset-presence` ("9 source file(s) of 2 released package(s)
changed, and this change declares 1 changeset(s)"), `changeset:check`
and `check-changeset-overwrite`, report-only, whose findings are the 3
dated appends with frontmatter unchanged.
- Docs: `check:doc-fences`, `check:doc-snippets` ("698 of 698 block(s)
judged, 0 failed"), `docs:check-links` ("Links are valid across 17 scan
roots"), `check:doc-examples`, `check:doc-types`,
`check:doc-example-ids`, `check:doc-example-readers` and
`check:skill-examples`.
- Others: `check:control-bytes`, `check:new-line-citations` ("0 new
citation(s)"), `check:handler-key-reads`,
`check:component-surface-parity` (report-only),
`check:designer-field-key-parity`,
`check:element-data-source-declaration`, `check:prompt-keys`,
`check:readme-exports`, `check:spec-symbols`, `check:test-path-roots`,
`check:unreferenced-sources` and `check-type-check-coverage`.
- `check-governed-queue-guard --test` over the 15 paths: NOT GOVERNED.
- **Narrowed lint against the merge base `cd5b19a`.** The 9 lintable
changed files ran through `eslint --format json`.
- With inline config: 0 errors and 75 warnings.
- With `--no-inline-config`: 1 error and 77 warnings. The one error is
the `react-hooks/static-components` line in `data-table.tsx`'s
row-action menu, inline-disabled at an untouched line, and it is
identical at base. Per-file error and warning counts are equal at base
and head; the new test file reads 0 / 0.
- The output judged 9 files and ignored 0.
- Invariance: `eslint.config.js` declares no `parserOptions` (so no
type-aware project), and no rule in `eslint-rules/` reads the disk, so
the diff cannot move an untouched file's verdict. The repo-wide lint is
CI's.
## Ablations, predictions written first, each restored to blob == HEAD
with `git diff HEAD` empty
Each ran through `ablation-replace.mjs`, with its anchor count proven 1
→ 0 on disk and restored.
- **A1** deleted the `selectionStyle` zod arm. The round-5 pin file read
"5 failed | 9 passed (14)", exactly the five predicted `selectionStyle`
rows. `tsc -p tsconfig.test.json` exited 2 with one error, at
`assertionUnmirroredMatchesLedger`.
- **A2** restored `ChatbotSchema.floatingConfig` to
`FloatingChatbotConfig`. vitest stayed green on the three chatbot pin
files (43 passed), since the change is type-level. `tsc` exited 2 with
exactly the four predicted errors: TS2578 in the round-5 pin file and in
the trigger-icon tripwire, TS2344 in the 7655 pin file, and one at
`assertionDriftMatchesLedger`.
- **A3** deleted the `editable` allow-list row. `tsc` exited 2 with
exactly one TS2344, at `assertionRuntimeOnlyIsCallbackShapedOrNamed`,
and the parity file's vitest stayed 37 passed, as predicted.
## Acceptance notes
- **One non-vacuity leg was reshaped, not dropped.** The leg asserted
that the two unmirrored ledgers share at least one entry. This round
made them disjoint for real: `DataTableSchema`, the last pair in both,
left `UnmirroredDeclared`. Keeping the leg would have forced a key back
onto a ledger. It is replaced by a lit control on the same reader:
`KnownDrift` shares a pair with each unmirrored ledger, so the header's
`0` is a reading, not a name-normalisation artefact. The reasoning is in
the test's own comment.
- **Merged `origin/main` twice, never rebased:** `de4459a`, then
`c1b5767`. The second merge followed PR #11310, which edits
`complex.ts`. The ledger counts did not move with either merge.
- **PR #11312 (open) adds a `WiderThanDeclared` entry to the same parity
file.** The two diffs touch disjoint blocks. Whichever lands second
merges `main` and re-derives the totals by parser count.
- The optional `with-item-count` catalog id rename was not done, because
this round does not touch that file.
- Commit trailers are the model-free pair AGENTS.md requires.
- NOT MEASURED:
- the full `pnpm test` farm and the repo-wide lint (CI's);
- `apps/console` tests, because no file it owns changed;
- an at-tier contract record, which the seat owes on the landing head.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .changeset/6152-unmirrored-round4.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,3 +48,5 @@ minor bump, per the repository's version policy.
48
48
49
49
`displayMode` on the two chatbot types is unchanged: its refusal stays TypeScript-only, so stored
50
50
designer documents that carry `displayMode: 'floating'` parse exactly as before.
51
+
52
+
**Correction, 2026-10-01 (objectui#6152, round 5).** The "Mirrored" section above says that on a `chatbot` node `floatingConfig` stays unvalidated. That was true when this change was written, and it no longer is: objectui#6152 round 5 retired `floatingConfig` on the `chatbot` type, so writing it on a `chatbot` node is now a `tsc` error and a parse error that names `chatbot-floating`. The `chatbot-floating` node keeps its `floatingConfig`, judged member by member, as this entry says.
feat(types)!: retire `data-table`'s `selectionStyle` and `chatbot`'s `floatingConfig` on both faces, and stop teaching `data-table`'s inline-edit flags as authored keys (objectui#6152, round 5)
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`, so the tolerant
10
+
validator kept an authored value without examining it. Each is retired at once, with no alias
11
+
window:
12
+
13
+
-`data-table`: `selectionStyle` (`'always' | 'hover'`). The `data-table` renderer in
14
+
`@object-ui/components` honoured `'hover'` by hiding each row's selection checkbox until the
15
+
row was hovered, but nothing in this repository or in `objectstack` authored or produced the
16
+
key. The hover-only branch is removed: a selectable table always shows its row checkboxes,
17
+
which is what `'always'` and an unset key already did. Delete the key; `selectable` alone
18
+
turns selection on.
19
+
-`chatbot`: `floatingConfig`. The `chatbot` renderer never read it, so a value on a `chatbot`
20
+
node configured nothing. The trigger and panel it describes belong to the floating
21
+
presentation: author `type: 'chatbot-floating'` with `floatingConfig`. That node's
22
+
`floatingConfig` is unchanged on both faces, and it is still validated member by member.
23
+
24
+
For each retired key:
25
+
26
+
- the TypeScript member is now `?: never`, so writing it is a `tsc` error;
27
+
- the zod mirror refuses it by name at the key, on the tolerant validator (`AnyComponentSchema`,
28
+
`safeValidateSchema`) and on the strict authoring face (`StrictAnyComponentSchema`) alike. The
29
+
strict face used to refuse it as an unknown key with no guidance; the refusal now says what to
30
+
write instead.
31
+
32
+
Delete the key from any document or literal that carries it.
33
+
34
+
**Docs: `data-table`'s inline-edit flags are host-paired.**`editable` and `singleClickEdit`
35
+
stay declared on `DataTableSchema`, unchanged, but the `data-table` page no longer teaches them
36
+
as keys a document sets. The table only stages an edit, and saving it needs callbacks a host
37
+
supplies in code. `object-grid` sets both keys on the table it builds and supplies that save
38
+
path; a document that wants inline editing authors an `object-grid`. Their doc comments say
39
+
the same.
40
+
41
+
`@object-ui/types` and `@object-ui/components` are in the fixed release group, so this ships as a
Copy file name to clipboardExpand all lines: .changeset/7654-floating-chatbot-trigger-icon-tombstone.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -70,3 +70,5 @@ mirror must add the `retirementTombstone()` half at the same time and flip the c
70
70
rather than delete it into a vacuum.
71
71
72
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.
73
+
74
+
**Correction, 2026-10-01 (objectui#6152, round 5).** The correction above says the `triggerIcon` refusal is still type-level only on a `chatbot` node. That no longer holds: objectui#6152 round 5 retired `floatingConfig` itself on the `chatbot` type, on both faces, so a `chatbot` node refuses the whole key, `triggerIcon` with it, at compile time and at parse time. The only node that still takes `floatingConfig` is `chatbot-floating`, where `triggerIcon` is refused on both faces as described above.
Copy file name to clipboardExpand all lines: .changeset/7655-chatbot-registration-authoring-faces.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -118,3 +118,5 @@ the zod twins. The "twenty keys" above is kept as the reading of this change; th
118
118
objectui#5605 retirement entry states what the three faces declare now.
119
119
120
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.
121
+
122
+
**Correction, 2026-10-01 (objectui#6152, round 5).** The section above says `ChatbotSchema` keeps `floatingConfig` as a typed member, so the `triggerIcon` tombstone reaches `chatbot` nodes. That is no longer true: objectui#6152 round 5 retired `ChatbotSchema.floatingConfig` on both faces, because the `chatbot` registration never read it. The member is a `?: never` tombstone on the TypeScript face and a named refusal on the zod twin, so a `chatbot` node refuses the whole key. `ChatbotFloatingSchema.floatingConfig` is unchanged; it never inherited the base member.
0 commit comments