Repository navigation
refactor!: retire twelve node type keys; the dashboard emits plugin-dashboard:metric / metric-card (objectui#10859 batch 8, phase 2b) - #11453
Conversation
…859 batch 8, phase 2b) Ten keys are unregistered, each with a tombstone docblock at its old site: scatter-chart, dashboard-grid, form-analytics, import-wizard, shared-view-link, app-creation-wizard, branding-editor, dashboard-editor, navigation-designer and related-list. The metric and metric-card node keys take skipFallback, and both dashboard surfaces now emit plugin-dashboard:metric / plugin-dashboard:metric-card through one table in widgetDispatch.ts. The dashboard widget vocabulary is unchanged. Regenerates the CLI known-schema-types list, repins the ratchet (REFUSED_AT_TYPE 36 to 24, NAMESPACED 389 to 379), corrects the key tables, and adds per-file doc-type exemption rows for the metric widget sites. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…aced keys; mount the grid with its own dataSource prop (objectui#10859 batch 8) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…lias, so the Metric Card example is judged (objectui#10859 batch 8) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
… metric-card key (objectui#10859 batch 8) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
… exemption rows name their declaring symbol (objectui#10859 batch 8) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…g entries the retirements overtake (objectui#10859 batch 8) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…rals, so the absence-collision gate can resolve them (objectui#10859 batch 8) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ 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
|
Contract reviewServed-tier: PR objectui#11453 on card objectui#10859, batch 8 phase 2b. Inputs: the card's body and all 59 comments (the triage 5860727647, the measured split 5861157913, seat 2's ruling 5861220023, the batch-8 claim 5945225235, the phase-1 report 5945491717, the seat ruling 5945530142 and its amendment 5945583855, the phase-2a report, ACCEPT and landing 5946031369 / 5946066584 / 5946649723, the phase-2b report 5948183744, the fork ruling 5948252391, the seat ACCEPT 5948265747); the PR body, its 60-file list (+965 / -395) and the net diff of the head against ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Reading time: 2026-10-02T08:44Z Generated by Claude Code |
Part of #10859
Clause-②: yes
Phase 2b of batch 8 on the family card. Twelve node type keys leave the registry: ten are unregistered, and the
metric/metric-cardnode keys lose their bare fallback while both dashboard surfaces emit the namespaced keys. Fourteen keys the ruling also named fail the premise gate, so they stay registered and are reported as forks with the evidence. Implemented byos-devfordomain:uiseat 1, sessionsession_01YLg8XqWGJ785fwQ5v4pH37. It follows the "Phase 2b" section of seat ruling5945530142, as amended by5945583855, and the coordinator's conditional premise gate.Premise gate: re-measured on
origin/main990a2d6 and laterEach key was searched for producers in source,
examples/**, the catalog, docs and the whole objectstack tree at6c5bef5f, and for runtime emission.scatter-chartdashboard-gridsdui-parserlint, which reads it)form-analytics,import-wizard,shared-view-linkapp-creation-wizard,branding-editor,dashboard-editor,navigation-designerrelated-listmetric,metric-cardDashboardRenderer,DashboardGridLayoutskipFallback: truepie-chart,donut-chart,radar-chartpage-headersidebar-*Fork 1:
pie-chart,donut-chart,radar-charthave an in-repo producerpackages/plugin-charts/examples/chart-examples.tsexportspieChartExample,donutChartExampleandradarChartExample, which authortype: 'pie-chart','donut-chart'and'radar-chart'. objectui#7401's describe block "the in-repo examples draw what they say" renders those three objects (ruling item 3 of that card). The file is not in the package'sfiles, so it does not ship, but it is a producer pinned by a ruled test.scatter-charthas no example there, so it passed the gate on its own and is retired.Fork 2:
page-headeris authored by objectstackOn objectstack
origin/main6c5bef5f, the spec conversions registry carriesPAGE_HEADER_COMPONENT_TYPES = new Set(['page:header', 'page-header'])and the conversionpage-header-subtitle-alias(toMajor 17, "Live window; retires at 18"). Its docblock says the key "is authorable here because PageComponentSchema.type is deliberately z.union([PageComponentType, z.string()])". It also says "The alias's entire reason to exist is out-of-repo consumer schemas" and "That registration is objectui's to retire, on its own schedule". Its fixtures author{ type: 'page-header', properties: {...} }.packages/spec. It searched only examples, apps, content, skills andpackages/studio.Fork 3: the
sidebar-*family's teaching rewrite has no targetNo new producer or emitter turned up. But the ruling ties this retirement to rewriting the four
components-basic-sidebardocuments andsidebar.mdx"to what the armedsidebarboth renders and accepts, measured by a render and a validate". The armedsidebarcallsuseSidebar(), which throws outside aSidebarProvider, and the only authored provider is thesidebar-providerprimitive this retirement removes. The measurements below come from a temporary probe test, run throughSchemaRendererwith both validator faces and deleted afterwards:sidebarwithtextchildrenInteractiveDemo:SidebarProviderwithdefaultOpen={false})data-state="collapsed"data-collapsible="offcanvas": shadcn's offcanvas collapse draws it off-screencollapsible: truedata-collapsible="true", which no CSS rule matches, so it shows only by accidentcollapsible: 'none'(the in-flow form)invalid_typeatcollapsibleside/variant/classNameunrecognized_keyssidebasic-sidebar.json(sidebar-providerroot)typetypeOnce
sidebar-provideris gone, nosidebardocument both draws visibly and validates, apart from thecollapsible: trueaccident. The four catalog documents would have nothing honest to be rewritten to. They cannot keep their retired types either, becausecheck:doc-typesadmits an exemption only where a retired value appears at a legitimate position. Forcing it through or quietly picking a fallback were both ruled out, so the ten stay registered and the teaching is unchanged. The options are in the report on the card:sidebarregistration supplies its ownSidebarProvider. Then a baresidebarrenders in any host and the teaching rewrite becomes possible.sidebar-provider(declare it) and retire the other nine.What changed
scatter-chart(plugin-charts), along with itsCHART_TYPE_KEYWORD_FAMILIESrow;dashboard-grid(plugin-dashboard);form-analytics(plugin-form),import-wizard(plugin-grid) andshared-view-link(plugin-view);app-creation-wizard,branding-editor,dashboard-editorandnavigation-designer(plugin-designer), under one block;related-list(plugin-detail).widgetDispatch.tsgainsDASHBOARD_NODE_TYPES(metricmaps toplugin-dashboard:metric,metric-cardtoplugin-dashboard:metric-card) andtoDashboardNodeType.metric-cardwidget-slot passthrough;metric/metric-cardnode in the legacycomponentenvelope.skipFallback: true. The widget vocabulary and the 2026-08-14metric-cardslot ruling are untouched.dashboardComponentslosesdashboard-grid. Its metric pair is now keyed by the namespaced type each entry serves, so iterating the map cannot re-create the retired bare keys.scatter-chartanddashboard-gridlazy stubs are gone.metric/metric-cardstubs, inregister-plugins.tsandpreview-gallery.tsx, passskipFallback: true.plugin-dashboard,plugin-form,plugin-gridandplugin-viewmdx pages and READMEs: the retired rows are gone, the metric rows read "none —skipFallback: true", and the call counts are updated.metric-cardexamples in the dashboard README now sit in a dashboard'swidgets[].schema-reference.mdsentence about the editable grid no longer calls itdashboard-grid.dashboard-gridregistration are updated.DOC_TYPE_EXEMPTIONSrows, only at widget-vocabulary positions:metric(aChartTypeSchemawidget kind) in four files;metric-card(aDASHBOARD_COMPONENT_WIDGET_TYPESslot entry) in four files.packages/cli/src/utils/known-schema-types.ts: 22 deletions, 12 bare keys and 10 namespaced twins.Tests re-pointed (each named a retired key)
scatter-chartrender cases becomechartwithchartType: 'scatter', plus an absence row for both spellings.plugin-charts:chartwithchartType: 'scatter';dashboard-gridtarget is gone;dashboard-gridtests:DashboardChart/seriesLabeltests and oneinvalidationRefetchcase mountDashboardGridLayoutdirectly, as theirDashboardRenderertwin already did.DashboardGridLayout.sduiDatasetPathbecomes the retirement pin: a storeddashboard-gridnode draws the unknown-type refusal, anddashboardis the control.MetricWidget.domPropsstandalone cases use the namespaced key;plugin-dashboardnamespace;plugin-dashboard:metric-card.scatter-chartjoins itsRETIREDset, and the list length is 6.dashboardComponentsparity: 7 keys, plus a row asserting that the retired keys stay out of both the map and the registry.Ratchet
REFUSED_AT_TYPE(bare)NAMESPACED_REFUSED_AT_TYPEThe ruling's target was 10. The difference is the 14 forks. The pin's comment names all 24 remaining keys: the ten the ruling kept (objectui#11440 and objectui#11441) and the fourteen forks, each with its reason. A new row pins the refused set to exactly that named list (
STILL_REFUSED_10859), so the comment cannot drift. Another new row asserts that the twelve are out of the population and still refused attype, that the ten twins are gone, and that both namespaced metric keys are still present. ⛔ Neither pin rises.Changesets
There is one
minorchangeset per released package whose code moved. Each carries a BREAKING (authoring) banner and a migration line per retired spelling:plugin-charts,plugin-dashboard,plugin-form,plugin-grid,plugin-view,plugin-designerandplugin-detail;cli(the regenerated list);console(the stubs).The
plugin-dashboardentry also covers:dashboardComponentsre-key;data-obj-typechange on KPI tiles (plugin-dashboard:metric).app-shellchanged one test file only, so it has no entry (the objectui#10393 precedent).Four pending changesets described a retired key in the present tense: 7401, 10528, 7509 and 7997. Each gains a dated note, and each one's frontmatter is byte-identical.
Local runs
All runs are from the worktree root. Heavy runs went through
os-verify-lock.At the final head
f0d0abe29:pnpm exec vitest run --maxWorkers=2and the listed paths:known-schema-types-derivation-5115,check-known-types,registry-bare-name-collisionsandcheck-doc-component-types.test.ts;unit-registry-absence-collision;metric/metric-cardtype;@object-ui/typesdesigner tests that refactor(types,plugin-designer,i18n)!: retire the unread designer members objectui#11434's ruling settles as RETIRE, on both faces (PR 1 of 3) #11451 touched.Test Files 61 passed (61),Tests 1072 passed (1072), VERDICT command-exit 0.pnpm --filter @object-ui/plugin-designer type-checkandpnpm --filter @object-ui/cli type-checkboth exit 0, after rebuilding their closures (refactor(types,plugin-designer,i18n)!: retire the unread designer members objectui#11434's ruling settles as RETIRE, on both faces (PR 1 of 3) #11451 changed@object-ui/types).pnpm check:doc-types(886 registered + 290 exempted type sites; 45 key-table keys judged, 45 registered);pnpm check:doc-snippets(775 of 775 blocks judged, 0 failed, after its scoped build);pnpm check:doc-example-idsandpnpm check:doc-fences;python3 scripts/regenerate-catalog-index.py --check;node scripts/markdown-test-inputs.mjs --audit;node scripts/check-doc-links.mjs;node scripts/check-changeset-presence.mjs(37 source files of 10 released packages, 9 changesets);node scripts/regenerate-known-schema-types.mjs --check;check:registry-bare-names,check:prompt-keys,check:readme-exports,check:control-bytes,check:new-line-citations(0 new);changeset:check,check:pending-changeset-literals,check:changeset-claims.At
9eb0f580e(after the firstmainmerge; the code is the same as the final head apart from #11451 and one test file):check:doc-examples,check:handler-key-reads,check:spec-symbols,check:component-surface-parity,check:test-path-roots;check:element-data-source-declaration,check:unreferenced-sources,check:doc-example-readers,check:self-import;check:vi-mock-inherit,check:vi-mock-specifiers,check:side-effects-array,docs:check-links;check:sdui-registration-pins(17 of 17 present, afterpnpm --filter @object-ui/console build).pnpm --filter X type-checkexits 0 forplugin-charts,plugin-dashboard,plugin-form,plugin-grid,plugin-view,plugin-designer,plugin-detail,cli,app-shellandconsole. This ran afterpnpm --filter '@object-ui/console^...' --filter '@object-ui/cli^...' build.eslint --no-inline-config --format jsonover the 38 changed ts/tsx/mjs files gives 0 errors.plugin-formindex 23 to 22 andplugin-gridindex 16 to 14, because the removed renderers carried theany.eslint.config.js. It sets noprojectService/parserOptions.project, so no untouched file's verdict can move. Fullpnpm lintis CI's.Earlier wide runs, before the fixes listed:
packages/plugin-view/ packages/plugin-designer/ examples/schema-catalog/test/: 137 files, 3074 tests, all passed.plugin-form,plugin-gridandplugin-detail: 27 files passed.app-shell/react/plugin-report/components/scripts: all passed.packages/plugin-dashboard/: 159 of 160 files passed. The README-harness file was red and was re-run green after its fix.packages/plugin-charts/ packages/cli/: 109 of 110 files passed. The recogniser file was red and was re-run green.apps/console/src/__tests__/plus the sweep plus the doc-types gate test: 45 of 47 files passed. The stubs test and the exemption-shape pin were red and were re-run green.Reverse verification
The prediction was written to the scratchpad before either leg ran.
BASE leg. The thirteen changed source files went back to BASE
990a2d616, the new and edited tests stayed, and the five pin files ran.sduiDatasetPath, 1 chart-family 7401 and 4 console stubs, with the controls and earlier batch rows green.Tests 13 failed | 49 passed (62). The red tests are exactly those 13, including "refuses 36 registered bare key(s) attype; the pin is 24" and "refuses 389 … the pin is 379".git diff HEADis 0 lines, and status is 0 lines.Ablation.
skipFallback: truewas dropped from themetric-cardregistration withscripts/ablation-replace.mjs, run from../objectstack. The anchor went from 1 hit to 0, and the blob from8a84c9f79e32toea900ba0f0d1.known-schema-types-derivation-5115went red ("expected [ 'metric-card' ] to deeply equal []", plus the byte-for-byte regen case), and the map-parity retired row went red (registry keymetric-cardwasMetricCard). Result:Tests 3 failed | 14 passed (17).type; the pin is 24", withmetric-cardin the Refused list. The phase-2b row and the exact-set row were red too. Result:Tests 3 failed | 21 passed (24).git diff HEAD. A second trap restored the known-types file, and its blobfa94132ef625equals HEAD.Acceptance notes
DASHBOARD_WIDGET_HOST_TYPESinsdui-parserstill listsdashboard-grid, in both the objectui copy and the objectstack copy. It is now a reader of a retired key. It is left unchanged so the two copies stay in step. Carrier: none.ROADMAP.mdstill lists the four designer keys under "Registered". It is a dated progress list, so it is left as is.plugin-gridREADME key-table rows carried line addresses that were already stale onmain. Theimport-wizardrow is gone, and the others are untouched.MetricWidget.domPropscases (a) to (c) kept passing once their bare key stopped resolving, because negative assertions over an "Unknown component type" panel stay green. Pointing them at the namespaced key makes them bite again.DashboardGridLayoutis no longer swept by the DOM-leak sweep, since it is not a registered widget any more.chart.type: 'scatter-chart'now reaches the genericchartwith no derived family. The changeset states this.Generated by Claude Code