Uh oh!
There was an error while loading. Please reload this page.
feat(types)!: retire DataTableSchema.toolbar — declared everywhere, read nowhere (objectui#6881) - #7066
feat(types)!: retire DataTableSchema.toolbar — declared everywhere, read nowhere (objectui#6881)#7066os-sam wants to merge 1 commit into
Conversation
…ead nowhere (objectui#6881) Maintainer ruling 2026-08-31 (option A: retire, do not wire): the key was declared on both published faces, documented, mirrored — and no renderer ever mounted it. An authored toolbar got a green document and a blank result. Both faces tombstoned in the same stroke, per the house ADR-0049 convention: - TS: `toolbar?: never` (deletion would fall through to BaseSchema's `[key: string]: any` and be silently admitted again) - Zod: `retirementTombstone()` — refusal carries the remediation (use the built-in chrome: searchable / exportable) The mirror-wider-than-declared drift (single-node spelling only the mirror accepted) dies with the key: both faces now agree by refusing both spellings. Pinned in data-table-toolbar-retired.test.ts: envelope-asserted refusal on both spellings, remediation text derived-equal with .describe(), absent stays valid, sibling emptyAction still accepted (counter-probe), key stays declared (route guard), plus the compile-time half via @ts-expect-error in the type-checked test program. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-sam
commented
Aug 31, 2026
This PR is green, mergeable, and deliberately NOT armed for auto-merge. It needs a human, and the Stating it once so the PR does not read as forgotten. #6881's ruling is explicit about the gate, quoted from the card:
The label is applied, the changeset carries the BREAKING declaration, CI is green and there is no conflict. Arming auto-merge would merge this the moment the queue reached it, which would bypass the review chain the ruling prescribed — so the hold is the ruling being followed, not caution.
What is needed: a contract review per the ruling. When it passes, arm auto-merge (squash) — the head has not moved since CI went green, so nothing else is owed. This seat's shift has ended; no further check-ins are scheduled against this PR. Handover for the next Generated by Claude Code |
Fixes#6881
Executes the maintainer ruling of 2026-08-31 (director batch 5, item 2), quoted verbatim from the card:
CONTRACT REVIEW: this PR narrows a published validator's accept-set (ruling clause 4: "条款②:yes(收窄已发布接受集)——PR 建立时挂
needs:contract-review走复审链;changeset 带 BREAKING 记号"). The label is applied at creation per that clause.Premises re-verified on this PR's base (85b4957), per the executor prerequisites
Line numbers re-located with git grep, not quoted from the card; the read-point census re-run with the card's positive control, not cited from it.
packages/types/src/data-display.ts:675—toolbar?: SchemaNode[], insideDataTableSchema(interface opens at line 650)packages/types/src/zod/data-display.zod.ts:244— union of one node or an array of nodes,.optional()data-table.tsxcontains the word at lines 986 and 1211 only — both prose comments; noschema.toolbarread repo-wide (remaining hits are i18n keys such asgantt.toolbar.refresh, ARIA roles, and same-named React props:PreviewShelltoolbar,toolbarAddon,toolbarActions)emptyAction— same interface, same SchemaNode shape — hitsdata-table.tsx:2118-2119, mounted throughSchemaRenderer; the zero above is a reading, not a blind queryzod-mirror-parity.test.ts— zero occurrences of the word across all four ledgersWhat changed — both faces, one stroke
data-display.ts): the live membertoolbar?: SchemaNode[]becomes the tombstonetoolbar?: never, with the ADR-0049 docblock carrying the measurement and the ruling.data-display.zod.ts): the union becomesretirementTombstone(...), so the refusal carries its remediation in the parse message AND the.describe()metadata (one string, both channels — the objectui#6931 mechanism).packages/types/src/__tests__/data-table-toolbar-retired.test.ts): envelope-asserted refusal on both spellings, remediation text asserted derived-equal with the describe text, boundary legs on both sides, route guard against softening the tombstone into a deletion, and the compile-time half via ts-expect-error directives verified present in the type-checked program (tsc listFiles count = 1 for the new file).On the ruling's "TS 成员删除" wording: the live TS member is deleted and the house tombstone stands in its place, rather than the line being removed outright. Removing the line entirely would fall through to BaseSchema's string index signature and be admitted as
anyagain — silently, even at fresh literals (measured and pinned bydataTableSchemaSlot-6459.test.ts: a bogus key on a bareDataTableSchemaliteral compiles). The ruling's own headline verb is 「同笔墓碑化」 and its pin ("authored toolbar flips to an authoring-time loud rejection") is only achievable through the tombstone; the same reasoning is already house law intimeline-timescale-retired.test.tsand theStaticTableColumnretirement.Accept-set delta — exactly what an author could write before and cannot after
Could write before (validated green, rendered nothing, no signal anywhere):
{ "type": "data-table", "columns": [{ "header": "Name", "accessorKey": "name" }], "data": [], "toolbar": [{ "type": "button", "label": "Refresh" }] }Also could write before — the spelling only the Zod mirror accepted (the TS face always refused it; this was the card's secondary observation, the mirror-wider-than-declared drift):
{ "toolbar": { "type": "button", "label": "Refresh" } }After this PR, both fail validation with the same envelope — code
invalid_type, pathtoolbar, expectednever, message:Nothing else stops validating. That is the whole delta: one key, both spellings.
Boundary proven on both sides (a change that refuses too much would pass a refusal-only test):
emptyAction(the census's positive control, actually mounted) — ACCEPTED. Both pinned.The rider settles by construction (PM triage clause): retiring both faces in the same stroke makes them agree by refusing both spellings, so the TS-vs-mirror shape divergence dies with the key — it was deliberately not "fixed first". The pin test keeps the single-node leg so the agreement is measured, not assumed.
Documents in this repo that would newly fail: NONE (enumerated, not assumed)
Swept fixtures, examples, catalog, docs and apps for authored
toolbaron a data-table:examples/schema-catalog/src/schemas/components-complex-data-table/*.json— recursive key scan: zerotoolbarkeys at any depth.content/docs/components/complex/data-table.mdx— zero occurrences of the word.content/docs/api/schema-reference.md— two occurrences, both prose about ObjectGrid's own runtime chrome, not authored keys.toolbar:authoring spellings — every hit is an i18n locale key, an ARIA role in tests, or an unrelated React prop (PreviewShell,toolbarAddon,toolbarActions); thecatalog-meta.json"toolbar buttons" description refers to a card that composes buttons by hand, not the retired key.packages/typesexamples and tests, the objectui#6882 declared-keys pin, and the objectui#6459 slot pin — zero references to the key.Changeset — BREAKING marker, graded per repo law
.changeset/6881-retire-data-table-toolbar.mdbumps@object-ui/typesminor and leads with "Breaking for authored metadata:", enumerating the delta and migration. It is deliberately NOT a literalmajor: AGENTS.md 版本号策略 reserves the fixed group's major for tracking@objectstackacross a major, spells out "objectui 自身的破坏性变更也标minor(在正文里写清 breaking 语义即可)", andscripts/check-changeset-no-major.mjs(changeset-guard workflow) exits non-zero on anymajorchangeset — a literal major cannot land. This matches the landed precedent for the closest cousin narrowing (.changeset/5120-retire-data-table-name-alias.md). The dispatch order's "(major)" gloss is thereby implemented as the ruling's actual requirement — a BREAKING-marked changeset — under the repo's mechanically-enforced grading; flagged here so the contract-review chain can veto.Verification (all on head 7511392 unless noted)
pnpm exec vitest run --maxWorkers=2 packages/types(root-relative form): 80 files, 977 tests passed — includes the new pin file and the untouched parity ledgers staying green.pnpm run type-checkinpackages/types(all three tsconfigs): green, with the two ts-expect-error directives consumed — the compile-time refusal direction is proven by their being used, andtsc -p tsconfig.test.json --listFilesconfirms the new test file is in the checked program.@object-ui/typesrebuilt (toolbar?: neverconfirmed present indist/data-display.d.ts:654); a consumer-side probe inpackages/plugin-gridimporting the package by name goes RED on the toolbar write (TS2322 at the property) and GREEN with the key removed; probe deleted, tree clean.check:control-bytesgreen (5858 files);check:doc-typesgreen (185 docs, 1068 blocks); changeset guard (check-changeset-no-major.mjs) green; targeted eslint (plain form) on the three changed source files: 0 errors.check:doc-snippets: exit 2 = PRECONDITION NOT MET locally (needs 20 packages built — the farm build CI owns). Declared narrowing in its place: the census above measured zero doc snippets authoring the key, and CI runs the full gate on this PR.Generated by Claude Code
Generated by Claude Code