Skip to content

refactor!: retire twelve node type keys; the dashboard emits plugin-dashboard:metric / metric-card (objectui#10859 batch 8, phase 2b) - #11453

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-10859-batch8-phase2b
Oct 2, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-10859-batch8-phase2b

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

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-card node 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 by os-dev for domain:ui seat 1, session session_01YLg8XqWGJ785fwQ5v4pH37. It follows the "Phase 2b" section of seat ruling 5945530142, as amended by 5945583855, and the coordinator's conditional premise gate.

Premise gate: re-measured on origin/main 990a2d6 and later

Each key was searched for producers in source, examples/**, the catalog, docs and the whole objectstack tree at 6c5bef5f, and for runtime emission.

key producers runtime emission disposition
scatter-chart 0 0 retired (unregistered)
dashboard-grid 0 (objectstack names it only as a host type in its own sdui-parser lint, which reads it) 0 retired (unregistered)
form-analytics, import-wizard, shared-view-link 0 0 retired (unregistered)
app-creation-wizard, branding-editor, dashboard-editor, navigation-designer 0 0 retired (unregistered)
related-list 0 0 retired (unregistered)
metric, metric-card 0 standalone; the dashboard WIDGET vocabulary only DashboardRenderer, DashboardGridLayout emitter moved (M3 option A), skipFallback: true
pie-chart, donut-chart, radar-chart 1: see fork 1 0 fork, still registered
page-header objectstack: see fork 2 0 fork, still registered
the ten sidebar-* only the four catalog documents the ruling orders rewritten 0 fork, still registered: see fork 3

Fork 1: pie-chart, donut-chart, radar-chart have an in-repo producer

packages/plugin-charts/examples/chart-examples.ts exports pieChartExample, donutChartExample and radarChartExample, which author type: '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's files, so it does not ship, but it is a producer pinned by a ruled test. scatter-chart has no example there, so it passed the gate on its own and is retired.

⚠️ Phase 1 counted this file as source without classifying it as a producer. That miss is why the ruling listed all four chart aliases together.

Fork 2: page-header is authored by objectstack

On objectstack origin/main 6c5bef5f, the spec conversions registry carries PAGE_HEADER_COMPONENT_TYPES = new Set(['page:header', 'page-header']) and the conversion page-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: {...} }.

⚠️ Phase 1 did not search objectstack's packages/spec. It searched only examples, apps, content, skills and packages/studio.

Fork 3: the sidebar-* family's teaching rewrite has no target

No new producer or emitter turned up. But the ruling ties this retirement to rewriting the four components-basic-sidebar documents and sidebar.mdx "to what the armed sidebar both renders and accepts, measured by a render and a validate". The armed sidebar calls useSidebar(), which throws outside a SidebarProvider, and the only authored provider is the sidebar-provider primitive this retirement removes. The measurements below come from a temporary probe test, run through SchemaRenderer with both validator faces and deleted afterwards:

node host render tolerant strict
bare sidebar with text children no provider throws "useSidebar must be used within a SidebarProvider." ok ok
the same the docs-site wrapper (InteractiveDemo: SidebarProvider with defaultOpen={false}) mounts, but data-state="collapsed" data-collapsible="offcanvas": shadcn's offcanvas collapse draws it off-screen ok ok
collapsible: true docs-site wrapper data-collapsible="true", which no CSS rule matches, so it shows only by accident ok ok
collapsible: 'none' (the in-flow form) docs-site wrapper renders in flow refused, invalid_type at collapsible refused
side / variant / className docs-site wrapper renders ok refused, unrecognized_keys side
today's basic-sidebar.json (sidebar-provider root) docs-site wrapper renders expanded refused at type refused at type

Once sidebar-provider is gone, no sidebar document both draws visibly and validates, apart from the collapsible: true accident. The four catalog documents would have nothing honest to be rewritten to. They cannot keep their retired types either, because check:doc-types admits 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:

  • A. The sidebar registration supplies its own SidebarProvider. Then a bare sidebar renders in any host and the teaching rewrite becomes possible.
  • B. Arm sidebar-provider (declare it) and retire the other nine.
  • C. Retire as ruled, and teach the bare node as host-provider-only (it draws collapsed and off-canvas in the docs host).

What changed

  • Unregistered, each with a tombstone docblock at its old registration site (the objectui#10393 / objectui#8760 route). Each docblock says what was there, why it went, and that the React export stays where one exists:
    • scatter-chart (plugin-charts), along with its CHART_TYPE_KEYWORD_FAMILIES row;
    • dashboard-grid (plugin-dashboard);
    • form-analytics (plugin-form), import-wizard (plugin-grid) and shared-view-link (plugin-view);
    • app-creation-wizard, branding-editor, dashboard-editor and navigation-designer (plugin-designer), under one block;
    • related-list (plugin-detail).
  • The metric emitter move (M3 option A).
    • widgetDispatch.ts gains DASHBOARD_NODE_TYPES (metric maps to plugin-dashboard:metric, metric-card to plugin-dashboard:metric-card) and toDashboardNodeType.
    • Both surfaces emit through that table for:
      • the static metric tile;
      • the metric-card widget-slot passthrough;
      • a metric / metric-card node in the legacy component envelope.
    • The two registrations take skipFallback: true. The widget vocabulary and the 2026-08-14 metric-card slot ruling are untouched.
  • dashboardComponents loses dashboard-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.
  • Console.
    • The scatter-chart and dashboard-grid lazy stubs are gone.
    • The metric / metric-card stubs, in register-plugins.ts and preview-gallery.tsx, pass skipFallback: true.
  • Teaching corrected.
    • The key tables in the plugin-dashboard, plugin-form, plugin-grid and plugin-view mdx pages and READMEs: the retired rows are gone, the metric rows read "none — skipFallback: true", and the call counts are updated.
    • The two standalone metric-card examples in the dashboard README now sit in a dashboard's widgets[].
    • The mdx Metric Card block is introduced as that slot entry.
    • The schema-reference.md sentence about the editable grid no longer calls it dashboard-grid.
    • Present-tense comments about the dashboard-grid registration are updated.
  • Doc gate. Eight per-file DOC_TYPE_EXEMPTIONS rows, only at widget-vocabulary positions:
    • metric (a ChartTypeSchema widget kind) in four files;
    • metric-card (a DASHBOARD_COMPONENT_WIDGET_TYPES slot entry) in four files.
  • Regenerated 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)

  • 7401 chart family: the two scatter-chart render cases become chart with chartType: 'scatter', plus an absence row for both spellings.
  • DOM-leak sweep:
    • the scatter arm is now swept through plugin-charts:chart with chartType: 'scatter';
    • the dashboard-grid target is gone;
    • the counts table is now 8 / 7, and 181 targets in all.
  • The dashboard-grid tests:
    • Six DashboardChart / seriesLabel tests and one invalidationRefetch case mount DashboardGridLayout directly, as their DashboardRenderer twin already did.
    • DashboardGridLayout.sduiDatasetPath becomes the retirement pin: a stored dashboard-grid node draws the unknown-type refusal, and dashboard is the control.
  • Metric tests:
    • the MetricWidget.domProps standalone cases use the namespaced key;
    • the 11022 strict-face test reads the inputs in the plugin-dashboard namespace;
    • the README harness now strips a one-line type alias, so the moved Metric Card example is judged.
  • cli recogniser: its unmodelled-type fixture is now plugin-dashboard:metric-card.
  • Console stubs test: scatter-chart joins its RETIRED set, and the list length is 6.
  • dashboardComponents parity: 7 keys, plus a row asserting that the retired keys stay out of both the map and the registry.

Ratchet

pin before after what moved
REFUSED_AT_TYPE (bare) 36 24 the twelve keys above
NAMESPACED_REFUSED_AT_TYPE 389 379 the ten namespaced twins of the unregistered keys

The 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 at type, that the ten twins are gone, and that both namespaced metric keys are still present. ⛔ Neither pin rises.

Changesets

There is one minor changeset 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-designer and plugin-detail;
  • cli (the regenerated list);
  • console (the stubs).

The plugin-dashboard entry also covers:

  • the dashboardComponents re-key;
  • the data-obj-type change on KPI tiles (plugin-dashboard:metric).

app-shell changed 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:

  • The union of 61 test files, run with pnpm exec vitest run --maxWorkers=2 and the listed paths:
  • Type-check: pnpm --filter @object-ui/plugin-designer type-check and pnpm --filter @object-ui/cli type-check both 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).
  • Exit 0 for each of:
    • 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-ids and pnpm 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 first main merge; the code is the same as the final head apart from #11451 and one test file):

  • Exit 0 for each of:
    • 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, after pnpm --filter @object-ui/console build).
  • Type-check: pnpm --filter X type-check exits 0 for plugin-charts, plugin-dashboard, plugin-form, plugin-grid, plugin-view, plugin-designer, plugin-detail, cli, app-shell and console. This ran after pnpm --filter '@object-ui/console^...' --filter '@object-ui/cli^...' build.
  • ESLint, narrowed:
    • eslint --no-inline-config --format json over the 38 changed ts/tsx/mjs files gives 0 errors.
    • Each file's error count equals its base blob's. Warnings are equal or lower: plugin-form index 23 to 22 and plugin-grid index 16 to 14, because the removed renderers carried the any.
    • The population is the root eslint.config.js. It sets no projectService / parserOptions.project, so no untouched file's verdict can move. Full pnpm lint is 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.
  • The registry-touching tests of plugin-form, plugin-grid and plugin-detail: 27 files passed.
  • 64 dashboard-consumer tests in 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.

  • Predicted: 13 red. That is 4 ratchet (count, namespaced, phase-2b row, exact set), 2 map parity, 2 sduiDatasetPath, 1 chart-family 7401 and 4 console stubs, with the controls and earlier batch rows green.
  • Observed: Tests 13 failed | 49 passed (62). The red tests are exactly those 13, including "refuses 36 registered bare key(s) at type; the pin is 24" and "refuses 389 … the pin is 379".
  • Restored: 13 blobs equal HEAD, git diff HEAD is 0 lines, and status is 0 lines.

Ablation. skipFallback: true was dropped from the metric-card registration with scripts/ablation-replace.mjs, run from ../objectstack. The anchor went from 1 hit to 0, and the blob from 8a84c9f79e32 to ea900ba0f0d1.

  • Leg 1 (source only): known-schema-types-derivation-5115 went red ("expected [ 'metric-card' ] to deeply equal []", plus the byte-for-byte regen case), and the map-parity retired row went red (registry key metric-card was MetricCard). Result: Tests 3 failed | 14 passed (17).
  • Leg 2 (list regenerated from the mutated source): the ratchet went red with "refuses 25 registered bare key(s) at type; the pin is 24", with metric-card in the Refused list. The phase-2b row and the exact-set row were red too. Result: Tests 3 failed | 21 passed (24).
  • Restored: the tool's restore reports blob equal to HEAD and an empty git diff HEAD. A second trap restored the known-types file, and its blob fa94132ef625 equals HEAD.

Acceptance notes

  • DASHBOARD_WIDGET_HOST_TYPES in sdui-parser still lists dashboard-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.md still lists the four designer keys under "Registered". It is a dated progress list, so it is left as is.
  • The plugin-grid README key-table rows carried line addresses that were already stale on main. The import-wizard row is gone, and the others are untouched.
  • The MetricWidget.domProps cases (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.
  • DashboardGridLayout is no longer swept by the DOM-leak sweep, since it is not a registered widget any more.
  • A legacy report section with chart.type: 'scatter-chart' now reaches the generic chart with no derived family. The changeset states this.

Generated by Claude Code

claude added 9 commits October 2, 2026 06:49
…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>
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 31 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/10756-html-tier-code-element.md

  • names packages/cli/src/utils/known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    • @object-ui/components — code joins the TAGS loop of html-elements.tsx: registered ui:code, sanitised like its siblings, declaring className and the children slot. An html author's ANGLE-BRACKETS(code) now renders a real code element with its text. - @object-ui/fields — BREAKING (authoring): the bare code key no longer resolves to the code-editor widget. code joins FIELD_TYPES_SKIP_FALLBACK, so the widget is registered field:code only. A node authored as bare { "type": "code", "value": … } now renders the html tier's code element (it draws children, not value); in a registry without @object-ui/components the bare key resolves to nothing. Migration: { "type": "code" } becomes { "type": "field:code" }. Form fields of type code resolve through the field: namespace and render the same editor as before. Released as minor under objectui's version policy; a breaking change never declares major. - @object-ui/core — code joins HTML_TIER_INTRINSICS, so getPublicConfigs() projects it stamped tier: 'html' and the regenerated sdui.manifest.json grows by one entry (the html tier declares 48 tags where objectui#10735 declared 47); div and kbd stay undeclared. - @object-ui/types — HtmlElementSchema (zod and TS) names code, keeping the JSON-surface declaration equal to the registration, as the objectui#8499 pin requires — so AnyComponentSchema (and objectui validate) now accepts { "type": "code" }, which it refused before. - @object-ui/cli — packages/cli/src/utils/known-schema-types.ts regenerates from the registrations and gains ui:code, so objectui validate and objectui check recognise it as a known schema type (the objectui#9533 and objectui#6416 precedent).

.changeset/10859-known-types-retired-keys.md

  • names packages/cli/src/utils/known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    BREAKING (authoring): KNOWN_SCHEMA_TYPES (packages/cli/src/utils/known-schema-types.ts, regenerated from the registration calls) no longer lists the 28 bare field-widget fallbacks retired in @object-ui/fields, nor tree / view:tree (@object-ui/plugin-tree) or view / plugin-view:view (@object-ui/plugin-view). objectui check now reports a root document of one of those types as an unknown type, and objectui validate keeps refusing it at type, as it already did.

.changeset/11068-grid-declared-keys.md

  • names schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was wrong. ObjectGridSchema declared eight keys the grid never read. An author who wrote description, emptyState, name, placeholder, rowSpecActions or bulkSpecActions on an object-grid got no type error, no validator refusal and no effect. The reference example in schema-reference.md taught description and showFilters as if they worked. It now authors only keys the grid reads.

.changeset/3917-retire-action-condition-branch.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • ActionCondition is removed from @object-ui/types (and from the barrel export). - ActionSchema.condition is retyped to the predicate the runtime actually honours: boolean | string | { dialect?: string; source: string } — the same three arms ActionRunner's own ActionDef.condition carries, and the same vocabulary visible and disabled use. - ActionConditionSchema is removed from @object-ui/types/zod (and from the zod barrel); the condition key now validates against that predicate union. - The two teaching sites (content/docs/core/enhanced-actions.mdx Conditional Execution, content/docs/api/schema-reference.md ActionSchema table) are rewritten to the live vocabulary: condition is a gate; a branch is expressed as separate actions with mutually exclusive conditions.

.changeset/6170-retire-timeline-dead-keys.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Also in this change: the in-repo example packages/types/examples/data-display-examples.json (its timeline node authored all three) is migrated to items / variant; the two content/docs/api/schema-reference.md snippets that authored events: [] now author items: []; and the plugin-timeline docs callout says retired rather than deprecated.

.changeset/6237-wizard-step-config-split.md

  • names content/docs/plugins/plugin-form.mdx → content/docs/plugins/plugin-form.mdx — edited by this change

    Documentation repair in the same stroke: the support table in the README and in content/docs/plugins/plugin-form.mdx still said formType: 'tabbed' sections drop the predicate. That stopped being true when the tabbed arm landed — the row now reads Yes, the surrounding prose no longer claims two inert arms or a diagnostic that fires for tabbed, and the wizard row stays No, which is still exactly true.

.changeset/6416-plugin-report-namespace.md

  • names packages/cli/src/utils/known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    packages/cli/src/utils/known-schema-types.ts is regenerated from the registrations, dropping report:report, report:report-viewer and report:spec-report.

.changeset/6650-listcolumn-wrap-implemented.md

  • names packages/plugin-grid/README.md → packages/plugin-grid/README.md — edited by this change

    @objectstack/spec declares ListColumn.wrap and describes it to authors as "Allow text wrapping", and packages/plugin-grid/README.md shows it in its authored-column example. No renderer anywhere implemented it. Long cell text stayed clipped to one line, with no error, no warning and no feedback of any kind — a promise made at authoring time and silently broken at render time.

.changeset/6896-retire-chart-inline-data.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ One correction to the record the ruling rests on. The ruling states zero authorship of a populated series[].data outside tests across packages/ / apps/ / examples/. The re-measurement finds one such site inside those roots — packages/types/examples/data-display-examples.json (2 series) — plus four outside them, in documentation: content/docs/api/schema-reference.md (3) and content/docs/core/report-schema.mdx (1).

.changeset/6939-kanban-column-cards.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Breaking, deliberately. KanbanColumn declared its card list as items in complex.ts and in the zod mirror complex.zod.ts. Every board reads cards. Measured on origin/main 78a3cc238: KanbanImpl.tsx reads .cards on 12 lines, KanbanEnhanced.tsx on 8, and bucketCardsIntoColumns twice more as col.cards || []; .items had zero read sites in either board (a same-shaped .title control on the same two files returns 8 and 3, so those zeros are readings and not a mis-shaped probe). Both catalog entries, the plugin docs and content/docs/api/schema-reference.md all author cards.

.changeset/6951-tree-view-data-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was measured, on this branch's base. TreeViewSchema declared two spellings for its one inline-nodes slot — nodes (read second) and data (read third: boundData || schema.nodes || schema.data || [] at renderers/data-display/tree-view.tsx:105), both declared by objectui#6150. data had been REQUIRED until 777e5c6f4 (PR fix(types): tree-view mirror stops requiring the limb it reads third (group 2 of objectui#6939) #7533) made it optional, so this retirement starts from a declared-and-optional member on both faces. The in-repo corpus at the retirement: seven tree-view nodes under examples/schema-catalog and packages/types/examples plus one content/docs fence — six on nodes, two on data (packages/types/examples/data-display-examples.json and content/docs/api/schema-reference.md), both rewritten; no package source authored either spelling.

.changeset/7122-spec-17-3-0-parity-reconciliation.md

  • names known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    user:profile is retired across all three sites. 17.3.0 dropped it from PageComponentType (measured: the enum went 34 → 32 options, lost set exactly ['user:profile', 'element:form'], gained set empty). objectui went on knowing it in three places, so all three moved together: the Studio palette exclusion ledger, PROTOCOL_COMPONENTS in renderers/placeholders.tsx, and the regenerated known-schema-types.ts the CLI checks schemas against. Nothing user-reachable went with it — neither type had a renderer, user:profile had only the dashed "Component Placeholder" scaffold, and the app shell's own profile affordance is a React slot, never this block type. A page schema still naming it now draws the loud "Unknown component type" panel rather than a silent grey box, which is this repo's standing treatment for a type outside the supported surface.

.changeset/7664-kanban-arm-plugin-dialect.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Migration. Author boards in the plugin dialect — objectName + groupBy for an object-bound board, or columns[].cards[] with badges for a static one. Replace DeclarativeKanbanSchema imports with KanbanSchema (from @object-ui/types, or the Zod KanbanSchema from @object-ui/types/zod; @object-ui/plugin-kanban re-exports the same KanbanSchema type). Delete draggable (drag-and-drop is always on) and column color (style a lane through className). content/docs/api/schema-reference.md's kanban section now documents this dialect.

.changeset/7694-chart-series-chart-type-alias-refusal.md

  • names normalizeChartSchema.ts → packages/plugin-charts/src/normalizeChartSchema.ts — edited by this change

    chartType is the renderer's INTERNAL spelling of type: the first limb of normalizeSeries' str(raw.chartType) ?? str(raw.type) (@object-ui/plugin-charts, normalizeChartSchema.ts), written by the internal-shape producers that hand dataKey-shaped arrays straight to ChartRenderer (ObjectChart, DatasetWidget; core/utils/chart-presentation translates authored type into it) and by nothing an author writes. Re-measured at implementation time, series-level, with lit controls (dataKey / name / type / color): docs 0, fixtures 0, designer inputs 0 (the chart registration's series is one code input), src literals 0, tests 9 — every one an internal-shape array that never meets this mirror. Limb ablation over 304 files / 5817 tests: deleting str(raw.chartType) ?? left all green; deleting the ?? str(raw.type) sibling went 2 red.

.changeset/7704-schema-registry-chatbot-keys.md

  • names packages/cli/src/utils/known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    packages/plugin-chatbot/src/renderer.tsx registers three components — chatbot, chatbot-enhanced and chatbot-floating — and SchemaRegistry mapped one of them. Since ComponentType = keyof SchemaRegistry is the published union, a consumer discriminating on it was told two registered keys do not exist: an author narrowing a node by ComponentType, or writing a RecordANGLE-BRACKETS(ComponentType, …) table, had no arm for either. The asymmetry that showed which half was wrong is that packages/cli/src/utils/known-schema-types.ts keeps its own parallel list containing both keys, precisely because this map did not.

.changeset/8114-detail-tab-activity-timeline.md

  • names plugin-dashboard/README.md → packages/plugin-dashboard/README.md — edited by this change

    README.md ships in this package's files, so the example went out in every tarball. DetailTabs renders a tab's content through ANGLE-BRACKETS(SchemaRenderer schema={toRenderableSchema(tab.content)} /), which makes content.type an SDUI node position judged by the component registry — so a reader copying the tab got the registry's Unknown component type panel (OBJUI-001) where the timeline should be. Same shape as the line-chart widget in plugin-dashboard/README.md (objectui#7896's census; fixed by objectui#7951) and the fourth known instance.

  • names scripts/check-doc-component-types.mjs → scripts/check-doc-component-types.mjs — edited by this change

    Which type replaces it was read off the registry rather than guessed, using the repository's own derivation — deriveRegistryKeys() from scripts/check-doc-component-types.mjs, the 649-key universe that gate judges against:

.changeset/8221-retire-legacy-string-sort.md

  • names content/docs/plugins/plugin-view.mdx → content/docs/plugins/plugin-view.mdx — edited by this change

    Docs teach the array only: content/docs/plugins/plugin-map.mdx, content/docs/plugins/plugin-view.mdx and packages/plugin-view/README.md.

  • names packages/plugin-view/README.md → packages/plugin-view/README.md — edited by this change

    Docs teach the array only: content/docs/plugins/plugin-map.mdx, content/docs/plugins/plugin-view.mdx and packages/plugin-view/README.md.

.changeset/8268-testid-emitted-as-data-testid.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    The other direction — retiring the promise — was considered and declined. It is what c1fe272ad did for BaseSchema.hidden, but that key had a working behaviour to describe and zero named consumers, and the ruling's decline turned on exactly that. This promise already has carriers outside the type declaration: content/docs/api/schema-reference.md states it as a table row and authors testId in that page's own base-schema example, @object-ui/cli's OBJECTUI_STRUCTURAL_KEYS identifies a file as an ObjectUI schema node by this key, at this change ObjectGridSlotKey / ObjectFormSlotKey pin it, SchemaBuilder.testId() writes it, and ADR-0054 C4 — shipped — reads "the renderer emits data-testid … derived from metadata".

.changeset/8499-node-slot-registered-arms.md

  • names scripts/check-doc-component-types.mjs → scripts/check-doc-component-types.mjs — edited by this change

    The defect, and the direction it ran. Nine type spellings sat at DECLARED node slots in this repository's own corpora and resolved in no arm of the component union. Eight were registered renderers with fixtures proving they draw; the ninth (my-component) is the reader's own plugin component and carries a written exemption in scripts/check-doc-component-types.mjs. A reader following content/docs/utilities/runner.mdx's own instruction — "copy one, wrap it in a page document … and save it as src/app-data/pages/index.json" — got a document that renders correctly in the browser and is refused by objectui validate. That is the expensive direction: the likely reaction is to stop trusting the validator.

  • names apps/console/src/register-plugins.ts → apps/console/src/register-plugins.ts — edited by this change

    line-chart is deliberately NOT armed. The card lists it among the eight as a live renderer; measured here it is not. apps/console/src/register-plugins.ts registers it as a lazy stub pointing at @object-ui/plugin-charts, and that package never registers the key, so it resolves to nothing at render time. Arming it would invent a capability rather than name one. __tests__/node-slot-registered-arms-8499.test.ts pins the absence together with its reason, so registering the key for real turns red.

.changeset/8653-listview-title-retired-rowactiondefs-pinned.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    title — retired. ListView resolved its export filename through schema.label || (schema as any).title. @objectstack/spec/ui's ListViewSchema refuses title by name (unrecognized_keys: ['title']) while ObjectGridPropsSchema accepts it; packages/types mirrors the platform contract rather than ruling over it, so declaring title on ListViewSchema would have made this repo accept what the platform save gate rejects. That asymmetry is also why objectui#6639 could take the declare branch for ObjectGridSchema.title one package over and this site could not. A parse-based census of apps/ examples/ content/ and packages/ found zero list-view nodes authoring title, so the retirement costs no author a filename. Over that same corpus the instrument reports three object-grid nodes carrying the key: two authored ones, both in content/docs/api/schema-reference.md, plus one that is not authored at all — packages/plugin-view/src/ObjectView.tsx composes title: schema.table?.title onto a grid node it builds, so it is a producer writing the key rather than an author declaring it. ObjectGrid's own title reads are untouched — they remain declared, ruled and read.

.changeset/8760-unfulfilled-chart-stubs.md

  • names content/docs/plugins/plugin-dashboard.mdx → content/docs/plugins/plugin-dashboard.mdx — edited by this change

    • At render. SchemaRenderer's lazy branch re-checks hasLazy(type) on every pass and returns the Loading ANGLE-BRACKETS(type)… placeholder. Registry.register() deletes a lazy entry only for keys the loaded module actually registers, so for an unfulfilled key the entry SURVIVES the load and every later pass takes the same branch. Measured on b775500af through the real chain: { "type": "line-chart" } painted role="status" / data-lazy-loading="line-chart" / Loading line-chart…, permanently. Not the OBJUI-001 panel the card expected — no alert, no error, no console warning. A skeleton that never resolves reads to a user as a slow network. - At authoring. A stub is enough to put a key into getKnownTypes(), so check:doc-types and the CLI's generated KNOWN_SCHEMA_TYPES snapshot both blessed all three. content/docs/plugins/plugin-dashboard.mdx taught "type": "line-chart" inside a card body, and every gate was green on it.
  • names apps/console/src/register-plugins.ts → apps/console/src/register-plugins.ts — edited by this change

    What moved. The stub lists in apps/console/src/register-plugins.ts and apps/console/src/preview-gallery.tsx (both loops, because the doc gate's key universe is their union — retiring one alone would have changed nothing observable); the dashboard doc snippet plus a note on how chart families are actually spelled; the regenerated KNOWN_SCHEMA_TYPES snapshot (six entries, three bare and three namespaced); and the line-chart leg of node-slot-registered-arms-8499.test.ts, whose premise this retirement changed and which reads the stub list rather than the file so the ⛔ comment left behind cannot satisfy it.

  • names apps/console/src/preview-gallery.tsx → apps/console/src/preview-gallery.tsx — edited by this change

    What moved. The stub lists in apps/console/src/register-plugins.ts and apps/console/src/preview-gallery.tsx (both loops, because the doc gate's key universe is their union — retiring one alone would have changed nothing observable); the dashboard doc snippet plus a note on how chart families are actually spelled; the regenerated KNOWN_SCHEMA_TYPES snapshot (six entries, three bare and three namespaced); and the line-chart leg of node-slot-registered-arms-8499.test.ts, whose premise this retirement changed and which reads the stub list rather than the file so the ⛔ comment left behind cannot satisfy it.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8802-8257-8008-kanban-gantt-family-retirement.md

  • names known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    ⚠️ objectui check will NOT flag either namespaced spelling. The CLI's known-schema-types.ts is generated from the repository's real registration calls, and the placeholder registration is a real one — so view:kanban and view:gantt are still on that list and still validate green, while the node renders a placeholder rather than a board. The bare kanban / gantt entries DID leave the generated list; only the namespaced pair survives, and only because of the placeholder. Grep your documents for the namespaced spellings directly; do not rely on objectui check to find them.

.changeset/9187-record-highlights-layout-two-values.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ The census behind this narrowing covers this repository only, and it found no in-repo authoring to migrate: every in-tree layout: 'grid' belongs to a different component (detail-view in content/docs/api/schema-reference.md and phase2-schemas.test.ts, ai-recommendations in packages/plugin-ai/README.md), and the one in-repo consumer of this interface that writes a layout (p1-spec-alignment.test.ts) writes 'horizontal'. So no document in this repository stops type-checking. A TypeScript consumer outside this repo that wrote grid is not observable from here and gets a compile error (TS2322) naming the key — which is why the FROM/TO is spelled out above.

.changeset/9280-record-highlights-entry-icon-retired.md

  • names packages/plugin-detail/src/index.tsx → packages/plugin-detail/src/index.tsx — edited by this change

    • packages/types/src/record-components.ts — RecordHighlightsComponentProps.fields[]'s object arm: { name; label?; icon?; type?; readonly? } → { name; label?; type?; readonly? }. The key is removed, not tombstoned: the contract's arm is $strict, so the refusal an author needs already exists upstream and arrives named (invalid_union at the entry). A ?: never tombstone buys nothing here — it is the remedy for a non-strict mirror that would otherwise strip in silence, which is not this arm. - packages/plugin-detail/src/renderers/record-highlights.tsx — the entry normalizer stops copying icon: f?.icon into the normalized entry. That read was unreachable, not merely unused: no author could feed it past the $strict arm, and HeaderHighlight renders no .icon on the far side either, so the copy had no consumer in either direction. - packages/plugin-detail/src/index.tsx — the registry manifest's fields input description sketched the entry as {name,label?,icon?,type?,readonly?} → {name,label?,type?,readonly?}. The inputs ARE the published contract (gen-manifest.ts serializes them into sdui.manifest.json and sdui-intrinsics.d.ts), so leaving the sketch standing would have gone on teaching AI and human authors a key that gets the whole document refused at publish.

.changeset/9533-dashboard-bare-key-converge-plugin-namespace.md

  • names preview-gallery.tsx → apps/console/src/preview-gallery.tsx — edited by this change

    What was wrong. apps/console declares the lazy stub for bare dashboard under plugin-dashboard — twice, in preview-gallery.tsx and register-plugins.ts — while this package registered the renderer as view:dashboard. Neither site passed skipFallback, so both also claimed the bare key (Registry.register and Registry.registerLazy share the meta?.namespace && !meta?.skipFallback branch, and registerLazy has no collision check at all, so nothing warned). Two consequences followed, and both were reproduced against a real Registry before anything here was written:

  • names register-plugins.ts → apps/console/src/register-plugins.ts — edited by this change

    What was wrong. apps/console declares the lazy stub for bare dashboard under plugin-dashboard — twice, in preview-gallery.tsx and register-plugins.ts — while this package registered the renderer as view:dashboard. Neither site passed skipFallback, so both also claimed the bare key (Registry.register and Registry.registerLazy share the meta?.namespace && !meta?.skipFallback branch, and registerLazy has no collision check at all, so nothing warned). Two consequences followed, and both were reproduced against a real Registry before anything here was written:

  • names scripts/check-doc-component-types.mjs → scripts/check-doc-component-types.mjs — edited by this change

    What changed. The renderer registers as plugin-dashboard:dashboard, the namespace every sibling plugin, both console stubs and the CLI whitelist already use, so the console stubs are cleared on load and all three claimants of the bare key name ONE full type. The retired view:dashboard key answers RetiredDashboardNodeTombstone — an inline refusal, plus a console.error carrying the same text — registered with skipFallback: true so it claims no bare key. Its spelling is withheld from the derived key universe by declaration in scripts/check-doc-component-types.mjs, the same disposition the RETIRED_FIELD_TYPES tombstones take, so objectui check names it in a file it recognises rather than blessing it; packages/cli/src/utils/known-schema-types.ts regenerates and loses that one entry.

  • names packages/cli/src/utils/known-schema-types.ts → packages/cli/src/utils/known-schema-types.ts — edited by this change

    What changed. The renderer registers as plugin-dashboard:dashboard, the namespace every sibling plugin, both console stubs and the CLI whitelist already use, so the console stubs are cleared on load and all three claimants of the bare key name ONE full type. The retired view:dashboard key answers RetiredDashboardNodeTombstone — an inline refusal, plus a console.error carrying the same text — registered with skipFallback: true so it claims no bare key. Its spelling is withheld from the derived key universe by declaration in scripts/check-doc-component-types.mjs, the same disposition the RETIRED_FIELD_TYPES tombstones take, so objectui check names it in a file it recognises rather than blessing it; packages/cli/src/utils/known-schema-types.ts regenerates and loses that one entry.

.changeset/calendar-view-schema-converge.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Runtime renderer behaviour is unchanged. @object-ui/plugin-calendar's README and content/docs/api/schema-reference.md are repaired to the converged surface in the same change, so no copy of the old contradiction survives.

.changeset/issue-5373-retire-crud-schema.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    crud had four declaration faces and no registered renderer, for the whole life of the key: the TS interface (packages/types/src/crud.ts), the zod mirror (packages/types/src/zod/crud.zod.ts), a dedicated branch in validateSchema that affirmatively PASSED it, and CRUDBuilder in @object-ui/core. A node spelling it painted the OBJUI-001 "Unknown component type" panel, and content/docs/api/schema-reference.md published it as reference material — so a reader (or an AI author) who copied the page got a red panel.

  • names api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Authoring crud is now REFUSED BY NAME rather than passed or silently ignored. validateSchema returns an error with code: 'RETIRED_TYPE' on schema.type — at any depth, since it is what validateChildren recurses with — so assertValidSchema throws and isValidSchema answers false. The message names the migration: object-grid for the record table with its toolbar, filters, pagination and row/batch actions, object-form for the create/edit form, and detail for the record view. api/schema-reference.md is rewritten around those shapes.

.changeset/object-view-unmirrored-keys-7779.md

  • names plugin-view/src/index.tsx → packages/plugin-view/src/index.tsx — edited by this change

    What was measured. Every reading was taken on the object-view node renderer (packages/plugin-view/src/ObjectView.tsx, registered by plugin-view/src/index.tsx) with schema.objectName / schema.layout as the positive controls of the same schema.KEY query, so each zero is a reading; the repo-wide census of viewTabBar finds the key in no source file outside @object-ui/types (two doc tables listed it as authorable and are corrected here). The spec side was read through the installed pin (@objectstack/spec@17.2.0, ui entry, 117 exported object schemas walked; control keys objectName / columns / navigation / listViews hit): the three spec-modelled keys are optional slots on ListViewSchema and ObjectListViewSchema; the six local keys have no spec slot anywhere.

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    listViews stays unmirrored, on the ruling's own fallback clause. The declaration's value is the local NamedListView — 64 declared top-level members (⚠️ re-taken at objectui#8980, which added the seventeen the protocol declares on this surface to the 47 this entry first measured), of which the renderer reads 21 off a named view. data is one of the 21 now: it used to reach the renderer through an as any cast on the named-view config in packages/plugin-view/src/ObjectView.tsx and be declared nowhere, and the objectui#8980 ruling declared it by name — objectui#7928's open half, answered. The spec's ViewSchema.listViews is a record of the STRICT ObjectListViewSchema, which requires columns and refuses options, ObjectQL tuple filters and default — that is, it refused the named views this package's own README and content/docs/api/schema-reference.md taught when this entry was written ({ label: 'All Users' } fails at columns; filter: [["owner", "=", "..."]] fails at filter.0), and objectui#8255 has since rewritten them in the spec shape. Mirroring the spec value would have lost documented behaviour; mirroring the local value would enforce 43 unread members (64 declared, minus the 21 that are both declared and read) into the contract — the very thing ruling B refused for the six local keys. The key therefore stays in the parity ledger with that measurement, pinned, until the maintainer decides its value type. It is not papered over with z.any().

.changeset/record-alert-cta-label-i18n-4998.md

.changeset/table-renderer-declared-column-contract-5350.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What makes this site different from its three siblings is that the alias was not merely tolerated, it was published. content/docs/api/schema-reference.md §TableSchema shipped a copyable { "name": "id", "label": "#" } example and a property row reading "Column definitions with name, label, …", while packages/types declared the opposite pair. Docs and type disagreed about one type they both call TableColumn, each internally consistent. Retiring the alias without correcting the page would have turned a documented, working example into a silently broken one, so both halves land together: the page now authors accessorKey/header. The same row also advertised a render property that TableColumn has never declared — the renderer's hook is cell — and that claim is dropped rather than re-spelled.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with c4ab6d09a (merge-base with origin/main): 47 file(s) changed outside .changeset/, read against 1980 pending declaration(s) that publish a body (2608 pending in total). · run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3551.1 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-B3cQsUfX.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.34KB 66.32KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.40KB 11.41KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.93KB 22.90KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 141.26KB 38.01KB
plugin-designer (index.js) 216.23KB 44.84KB
plugin-detail (index.js) 245.17KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 178.38KB 44.94KB
plugin-grid (index.js) 231.26KB 63.56KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 89.87KB 22.69KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f0d0abe296152a09936c81c8ccf3d508bddc2a84
Local-runs: none

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 origin/main; source at the head read with git show (the two dashboard surfaces, widgetDispatch.ts, normalizeChartSchema.ts, the five plugin barrels, Registry.ts, SchemaRenderer.tsx, the five documents the doc-gate rows name, and the check-changeset-presence header); the objectstack checkout for the spec's chart vocabulary and the sdui-parser mirror; the head's check-runs, polled until every run had completed. Not the dispatch order and not the dispatching seat's conclusions. Nothing built, run or re-run.

① Derived judgments

  1. Ten node keys unregistered, each with its namespaced twin — right. scatter-chart (plugin-charts), dashboard-grid (plugin-dashboard), form-analytics (plugin-form), import-wizard (plugin-grid), shared-view-link (plugin-view, namespace view), app-creation-wizard / branding-editor / dashboard-editor / navigation-designer (plugin-designer) and related-list (plugin-detail). At the head each ComponentRegistry.register(...) call is gone and a tombstone docblock stands where it was, naming what was there, why it went and where the capability lives. Every React component the changesets promise stays a named export: FormAnalytics (with FormAnalyticsProps), ImportWizard (with ImportWizardProps), SharedViewLink, RelatedList, DashboardGridLayout, and the four designer components with their *Props types. The two module-local renderers that went with the keys (FormAnalyticsRenderer, ImportWizardRenderer) were never exported, so no export surface narrows there; the unused useSchemaContext import leaves plugin-grid with them and Type Check is green. Grep of the head over non-test source, the console, examples and skills/ for the ten spellings at a type position: zero producers remain. The only hits are sdui-parser's DASHBOARD_WIDGET_HOST_TYPES (a reader, item ③.2) and three data-testid attributes inside the designer components, which are DOM test ids, not node types. objectstack at its local main authors none of the ten; its only dashboard-grid literals are its own sdui-parser test fixtures against a stub registry.

  2. metric / metric-card register with skipFallback: true, and both dashboard surfaces emit the namespaced key — right, and complete. Read at the head, DashboardRenderer's getComponentSchema has exactly three exits that can hand SchemaRenderer a metric node: the author-supplied widget.component (now toDashboardNodeType), the dispatch.family === 'metric' static branch (now DASHBOARD_NODE_TYPES.metric; its provider: 'object' sibling emits object-metric, unchanged), and the final slot passthrough (now toDashboardNodeType({ ...widget, ...options })). DashboardGridLayout.getComponentSchema carries the same three, through the same table. classifyWidgetType keeps metric in METRIC_LIKE_TYPES, so the WIDGET vocabulary is untouched, as the 2026-08-14 slot ruling requires. No other non-test source in the tree builds a bare metric / metric-card node or looks one up: the only dynamic registry read is SchemaRenderer's ComponentRegistry.get(evaluatedSchema.type); the console's preview-samples.ts and the designer's WIDGET_TYPES palette hold metric at widgets[].type, the widget vocabulary. registerLazy honours skipFallback (its bare-stub branch is guarded by !meta?.skipFallback), so the two console stub loops decline the bare key as the registrations do. The regenerated KNOWN_SCHEMA_TYPES drops the two bare keys and keeps plugin-dashboard:metric / plugin-dashboard:metric-card; the Test shards carry the derivation test's byte-for-byte regeneration case, and they are green on the head, so the committed list equals the derivation.

  3. dashboardComponents re-keyed — a public-export change, declared. The map is a named export of @object-ui/plugin-dashboard; its keys metric / metric-card become the namespaced spellings and dashboard-grid leaves. A consumer indexing the old keys breaks at compile; the changeset carries the FROM → TO line. DASHBOARD_NODE_TYPES and toDashboardNodeType are module-internal: none of the barrel's export blocks names them and nothing re-exports widgetDispatch, so the package gains no public export (no widening).

  4. A rendered KPI tile's data-obj-type now reads the namespaced key — a public observable, declared. SchemaRenderer stamps data-obj-type from the node's type, so the move is visible to CSS and e2e selectors. The plugin-dashboard changeset carries the selector migration; no non-test selector in the tree reads the old value.

  5. The scatter-chart family row removed — right. familyFromComponentType('scatter-chart') answers undefined at the head, so a node still spelled that way reaches the generic chart with the renderer's default family (the dev's acceptance note). Nothing spec-valid loses a family: the spec's chart vocabulary is scatter (objectstack ui/chart.zod.ts), DatasetReportRenderer dispatches on 'scatter', and objectui validate refused the retired spelling at type before this PR. The plugin-charts changeset states the consequence and the one-line fix. The pie-chart / donut-chart / radar-chart rows stay because their registrations stay; the 7401 pin holds table and registry equal in both directions, so a row without a registration would have gone red — the table is consistent with the fork.

  6. Doc gate: eight DOC_TYPE_EXEMPTIONS rows (metric in four files, metric-card in four files, across schema-reference.md, dashboard-filters.md, plugin-dashboard.mdx, the plugin-dashboard README and the types README) — right at this head. Every metric / metric-card type site in those five files was read: each sits in a dashboard's widgets[], in a widget.component envelope inside widgets[], in a literal typed DashboardWidgetSchema / DashboardWidgetSlotComponentSchema, or behind the types README's card() helper that wraps the entry in a dashboard. None is a standalone node, so no row covers a false teaching. Residual, the same as phase 2a's M2 answer: an exemption is per file and value, so a future standalone metric fence in one of these five files would pass unjudged. That is the gate's grain, not this PR's defect; Doc Component Type Check is green.

  7. Teaching corrected — right. The four key tables (mdx and README) lose the retired rows and the metric rows read "none — skipFallback: true"; the call counts match the barrels at the head (dashboard 7 live calls plus the view:dashboard tombstone loop the table deliberately omits; form 5; grid 2; view 5). The two standalone metric-card README examples now sit in a dashboard's widgets[], and the README harness strips a one-line type alias so the moved block is judged rather than skipped. schema-reference.md no longer calls the editable grid dashboard-grid. Doc Snippet Type Check, README Export Check, Internal Docs Link Check and Doc Example Id Check are green.

  8. Ratchet — right. REFUSED_AT_TYPE 36 → 24 (the ten unregistered plus the two skipFallback keys); NAMESPACED_REFUSED_AT_TYPE 389 → 379 (the ten twins of the unregistered keys only; the metric pair keeps its namespaced keys, so the arithmetic is consistent). STILL_REFUSED_10859 names the 24 as the ten the ruling kept plus the fourteen forks; one new row pins the refused set equal to that list and the list's length to the pin, another pins the twelve out of the population and still refused, the ten twins gone, the two namespaced metric keys present, and chart / dashboard / record:related_list as lit controls. Neither pin rises. The seat's target of 10 is not reached because of the fourteen forks, and the pin's docblock says so.

  9. Tests re-pointed — right. Seven dashboard tests that reached DashboardGridLayout through the registry now mount it directly, as their DashboardRenderer twins already did; sduiDatasetPath becomes the retirement pin (a stored dashboard-grid node draws the unknown-type refusal, dashboard as control); the 7401 scatter rows become chart + chartType: 'scatter' plus an absence row under both spellings with radar-chart as lit control; the app-shell sweep keeps the scatter arm swept through plugin-charts:chart; MetricWidget.domProps points at the namespaced key, and its case (e) asserts the new data-obj-type value positively, so the file is no longer green over an unknown-type panel; the console stubs test adds scatter-chart to its RETIRED set and expects 6; map parity pins 7 keys plus a literal-per-key absence row; the cli recogniser fixture is plugin-dashboard:metric-card, which KNOWN_SCHEMA_TYPES carries and safeValidateSchema still refuses.

  10. The PR body. The premise-gate table, the three fork tables, the ratchet table and the changeset list agree with the tree wherever the tree can answer (60 files, +965 / -395; nine new changesets; four dated notes that are pure appends, each hunk starting after the entry's existing body). The "Local runs" and "Reverse verification" sections are the dev's recordings and were not re-run here.

② Semver level

  • Nine minor changesets, one per released fixed-group package whose published source moved — plugin-charts, plugin-dashboard, plugin-form, plugin-grid, plugin-view, plugin-designer, plugin-detail, cli, console. This is objectui's rule for a breaking change: the fixed group never declares major (the no-major guard), so breaking semantics go in the body, and each entry carries the BREAKING (authoring) banner, a FROM → TO migration line per retired spelling, and a Clause-②: yes line. Seven name the (narrowing) arm; the cli and console entries name none, which the closed pair's "at most one arm" allows. Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read and Changeset Overwrite Report are green on the head.
  • @object-ui/app-shell carries no entry, correctly. Its one changed file is a test under src/__tests__/; the presence gate asks the change to declare a changeset, which it does nine times over, and the fixed group versions app-shell with the rest. A test-only change has nothing to tell an upgrading reader (the objectui#10393 and phase-2a precedent).
  • Clause-②: yes holds on the claim 5945225235, on the PR body's third line and in every changeset: the registry accept set narrows (twelve bare keys and ten namespaced twins stop resolving), a public export's keys change, and the generated KNOWN_SCHEMA_TYPES list shrinks. No packages/spec/src/** path is touched (this is an objectui PR), so the declaration arm alone is what makes this review owed, and it was declared. The body's line carries no arm, the changesets say (narrowing); consistent.
  • The four dated notes on pending entries 10528, 7401, 7509 and 7997 append a paragraph each and leave the frontmatter bytes untouched, so no other card's bump moves.

③ Boundary flags

  1. Dev open_questions (report 5948183744): three forks, every one answered by the seat in 5948252391 before this review ran. Fork 1 (pie-chart / donut-chart / radar-chart, a producer in the unpublished examples/chart-examples.ts pinned by the 7401 item-3 test) → A, migrate the examples then retire, phase 2c, no edit to this PR. Fork 2 (page-header) → B, retire now; the seat corrected the dev's reading of the objectstack conversion: page-header-subtitle-alias renames a KEY, its fixtures are test data, and the type registration is objectui's to retire. Fork 3 (the ten sidebar-* primitives) → A conditional, phase 2d, with the provider-shadowing premise verified first and the collapsible family member riding along. None of the three changes this head. One consequence for the next phase: the ratchet docblock at this head states fork 2's reason as "objectstack's page-header-subtitle-alias conversion and its fixtures author it", which is the reading the seat has since corrected; the phase-2c PR that removes page-header from STILL_REFUSED_10859 rewrites that sentence with the key, and nothing rests on it meanwhile. Non-blocking.

  2. Acceptance notes (PR body), each. (a) sdui-parser's DASHBOARD_WIDGET_HOST_TYPES still lists dashboard-grid in both repos — read in both: identical two-entry sets; it is a reader of a retired key and the lint simply never matches it, so it is harmless, and dropping it is a two-repo edit that keeps the mirror in step: accepted, phase 2c may carry it. (b) ROADMAP.md lists the four designer keys under "Registered" — a dated progress list, dropped. (c) The plugin-grid README key-table rows carry cross-file line addresses that were stale before this PR; the PR removed the import-wizard row and added no new address (Line Citation Gate is differential and green): accepted, with the note that objectui's rule asks for opportunistic repair on the next touch of that file. (d) The MetricWidget.domProps negative cases had gone vacuous once the bare key stopped resolving and are re-pointed: accepted, and item ①.9 records why the file now bites again. (e) DashboardGridLayout leaves the DOM-leak sweep's population because it is no longer a registered widget; the sweep's two ledgered dashboard rows are the metric pair, not the grid: accepted. (f) A legacy node spelled scatter-chart loses its derived family: judged in ①.5, declared in the changeset.

  3. Deviations declared across the batch. The worktree install used --config.engine-strict=false (a toolchain reading from phase 1, no file effect). The two merge commits carry git's default message; the PR lands by squash and the landing seat composes the trailer pair. The PR title and body carry no model identifier; the body footer is the session-URL form; Part of #10859 is the only card reference and there is no closing keyword, so the card stays open for phases 2c and 2d. The phase-1 misses (the chart examples counted as source but not as a producer; objectstack's packages/spec unsearched) are disclosed in the body, and the premise gate caught both.

  4. Governance and size. The file list hits no register row (skills/**, .claude/**, docs/adr/**, AGENTS.md, CLAUDE.md, docs/NORTH-STAR.md): not governed; 1,360 changed lines, under the 5,000 ceiling; head repo equals base repo. This record is therefore the Clause-② review the landing waits on, and on PASS the owning seat readies the draft and queues it. PR state at reading: draft, needs:contract-review on, auto-merge off, assignee mirrors the card, merge state behind, which the queue handles.

  5. Cross-repo. objectstack's Console Pin Gate builds objectui at the pinned .objectui-sha; this PR removes registry keys, not exports objectstack imports, so nothing there reds when it lands. The pin bump that later carries it regenerates the SDUI manifest, and the retired keys leave the manifest then — that is the bump's step, not this PR's.

  6. Checks on the head. 43 check-runs, every one bound to the head and completed: 40 success, 3 skipped by design (Test (coverage), its matrix row, dependabot), 0 failure. Lint, Type Check, Build & E2E, Test and all eight Test shards, Test (dist pins), Spec Main Shape Gate, Doc Component Type Check, Doc Snippet Type Check, README Export Check, Line Citation Gate, Control Byte Scan, the five Changeset checks, Governed Surface Queue Guard, the three Skill checks, Internal Docs Link Check, Build Docs, Bundle Analysis, Live E2E (informational), Pre-Install Import Graph Check, Inert vi.mock Specifier Check, Shell Escape Residue Scan, Action Ref Convention, Docs Route Eager Closure Check, Doc Example Id Check, Doc Fence Language Check and label are all success. Every check is green.

Implemented-by: claude/issue-10859-batch8-phase2b
Reviewed-by: session_01YLg8XqWGJ785fwQ5v4pH37

VERDICT: PASS

Reading time: 2026-10-02T08:44Z


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 08:45
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 08:46
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 37140f4 Oct 2, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10859-batch8-phase2b branch October 2, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants