Skip to content

refactor!: retire pie-chart, donut-chart, radar-chart and page-header; the chart examples author chart + chartType (objectui#10859 batch 8, phase 2c) - #11457

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

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-10859-batch8-phase2c

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #10859

Clause-②: yes

Phase 2c of batch 8 on the family card: four node type keys leave the registry under the seat's fork ruling 5948252391. Fork 1 is answered with route A: the three chart aliases retire after their one producer moves. Fork 2 is answered with route B: page-header retires. Implemented by os-dev for domain:ui seat 1, session session_01YLg8XqWGJ785fwQ5v4pH37. Base: origin/main 37140f4f5, after phase 2b (objectui#11453) landed. Phase 2d (the sidebar-* family) follows as its own PR and is untouched here.

Premise gate: re-measured after the example migration

Each key was searched at a type position across objectui (source, examples/**, the catalog, docs, skills/) and across objectstack origin/main 3937ad2f, and checked for runtime emission.

key producers runtime emission disposition
pie-chart, donut-chart, radar-chart 0, once examples/chart-examples.ts moved; objectstack 0 0 retired (unregistered)
page-header 0 in objectui; objectstack only in conversion fixtures and tests, two docblocks that cite it as an example key, and changelogs 0 retired (unregistered, plus its placeholder entry)

On page-header, the seat's corrected reading holds. The objectstack conversion page-header-subtitle-alias renames the KEY description → subtitle on both header spellings. Its docblock says it does not rewrite the type and that this registration "is objectui's to retire, on its own schedule". Its fixtures are test data. Nothing new turned up, so there is no fork.

What changed

The three chart aliases (fork 1, route A)

  • packages/plugin-charts/examples/chart-examples.ts: pieChartExample / donutChartExample / radarChartExample now author { type: 'chart', chartType: 'pie' | 'donut' | 'radar' }. objectui validate accepts each on both faces (measured).
  • The three registrations are unregistered, with their plugin-charts: twins and their CHART_TYPE_KEYWORD_FAMILIES rows. One tombstone note replaces them. The table now holds chart:bar alone.
  • The phase-2b scatter-chart tombstone now describes its old call instead of quoting it, because @object-ui/types' node-slot test reads quoted calls in comments as live registrations.
  • chart-family-from-type-7401.test.tsx:
    • The item-3 rows still render each example and assert that it draws pie / pie / radar marks and no bar. They now also pin type: 'chart' and the chartType, so an example cannot drift back onto a retired key.
    • "renders as itself" runs on chart:bar (both spellings) and on chart + chartType.
    • The donut-vs-pie family row and the explicit-chartType row moved to surviving spellings.
    • A new row pins the three keys absent under both spellings, with no family derived.
    • The scatter absence row's lit control is now chart:bar, because radar-chart is gone.
  • Console:
    • register-plugins.ts drops the three lazy stubs, and preview-gallery.tsx drops pie-chart.
    • The stubs test adds the three to RETIRED, moves its control to chart:bar and expects 3 stubs.
    • The CLI's 8760 control is now chart:bar, and so is the @object-ui/types node-slot reader's.
  • The DOM-leak sweep loses the three targets (one target per registered type). The counts are now 5 / 178.
  • A dated note is appended to phase 2b's .changeset/10859-retire-scatter-chart.md. It answers that entry's "wait on their own decision" sentence.

page-header (fork 2, route B)

  • @object-ui/layout: the page-header registration (bare plus layout:page-header) is replaced by a tombstone note, and the now-unused import goes. PageHeader stays a named export. registerLayout() now registers four keys.
  • @object-ui/components: 'page-header' leaves the opt-in PROTOCOL_COMPONENTS list. Without that, registerPlaceholders() would have kept the bare key registered, and the derivation would have kept blessing it (the ablation below measures exactly that).
  • Teaching:
    • content/docs/guide/layout.md and content/docs/layout/page-header.mdx replace the "alias is still accepted" passages with the retirement and a page:header example that validates.
    • The layout README's key list is corrected, and the guide's "registers four keys" sentence matches the source, as its pin requires.
  • Tests re-pointed:
    • page-header-authorable-keys.test.tsx keeps its name, because five files (and two changelogs) cite it by path. It now pins the retirement, with responsive-grid as the lit control, and keeps the PageHeader render rows of objectui#3789. The alias's declaration-surface describes went with the alias.
    • The layout containment census now has four registrations and pins that none declares the slot.
    • The catalog test's alias section becomes a retirement pin (unknown-component in the manifest, with page:header as control), and its navigation-renderer halves stay.
    • The side-effects bundle probe now looks for responsive-grid.
    • Comments and notes that described the alias in the present tense were updated in the layout tests, the site registrar, the 3904 pin, test-support's README, spec-tombstones and block-config.

Optional item: left on purpose

sdui-parser's DASHBOARD_WIDGET_HOST_TYPES still lists dashboard-grid. objectstack's copy of that module opens with "ported into this copy in lockstep (objectstack#12810)", so the mirror rule requires both copies to move together. Both are left as they are, with no cross-repo edit.

Ratchet

pin before after what moved
REFUSED_AT_TYPE (bare) 24 20 pie-chart, donut-chart, radar-chart, page-header
NAMESPACED_REFUSED_AT_TYPE 379 374 plugin-charts:pie-chart, plugin-charts:donut-chart, plugin-charts:radar-chart, layout:page-header, protocol-placeholder:page-header

The pin's docblock names the 20 that remain: the ten the ruling kept (objectui#11440 and objectui#11441) and the ten sidebar-* primitives (phase 2d). The fork-2 reason that the contract review flagged is rewritten with the key reading. STILL_REFUSED_10859 now holds 20, and its set-equality row holds. A new phase-2c row asserts that the four keys are out of the population and still refused at type, that the five twins are gone, and that chart and page:header are lit controls that are not refused. ⛔ Neither pin rises.

Changesets

Each is minor, with a BREAKING (authoring) banner and a migration line per spelling:

  • @object-ui/plugin-charts: the three aliases.
  • @object-ui/layout: page-header. Its migration lines are measured against objectui validate:
    • title / subtitle / actions go into page:header's properties;
    • icon has no page:header spelling (the contract refuses properties.icon by name), so drop it or compose PageHeader in JSX;
    • children has no page:header spelling either: the contract refuses a node-level children by name, and properties.children as an unrecognized key. Use properties.actions, or compose PageHeader in JSX.
  • @object-ui/components: the placeholder entry.
  • @object-ui/cli: the regenerated list.
  • @object-ui/console: the stubs.

app-shell, types and test-support changed test files only, so they have no entry. Pending entries 7401, 9910, 11044 and the 4761 app-shell entry gain dated notes, and phase 2b's plugin-charts entry gains one. Each note is a pure append, and each entry's frontmatter is byte-identical.

Local runs (final head ff1cb3c5a)

origin/main moved after the work was done, when objectui#11454 (objectui#11434 PR 2, types and plugin-designer) landed. It was merged before opening; the merge is clean and touches none of this PR's files.

  • Final union at ff1cb3c5a, through os-verify-lock, with pnpm exec vitest run --maxWorkers=2, in two calls:
  • Exit 0 at ff1cb3c5a:
    • pnpm check:doc-types and pnpm check:doc-snippets (after its scoped turbo build and a @object-ui/types rebuild);
    • 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 (20 source files of 7 released packages, 5 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, check:side-effects-array, check:handler-key-reads.
  • At c695a9611 (before that merge; this PR's own files are identical at both heads):
    • the same union in one call, with pnpm --filter @object-ui/plugin-charts --filter @object-ui/example-schema-catalog type-check: Test Files 137 passed (137), Tests 2006 passed | 9 skipped (2015), both type-checks Done;
    • exit 0 for check:doc-examples, 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, docs:check-links;
    • check:sdui-registration-pins (16 of 16 present, after pnpm --filter @object-ui/console build; page-header left the derived set).
  • At 5b35f07ac (differs from c695a9611 only in the 7401 case-title order):
    • pnpm --filter X type-check is Done for plugin-charts, layout, components, cli, types, test-support, app-shell and console, after building the console^..., cli^... and test-support^... closures.
    • packages/plugin-charts/ packages/cli/ apps/console/src/__tests__/ plus the types reader and the sweep: 157 files, 2368 tests, all passed.
    • packages/layout/ examples/schema-catalog/test/ plus 14 gate and reader tests: 88 files, 2927 tests, all passed.
  • ESLint, narrowed:
    • eslint --no-inline-config --format json over the 30 changed ts/tsx/mjs files gives 0 errors and 21 warnings.
    • Every file's error and warning counts equal its base blob's.
    • The population is the root eslint.config.js, which sets no projectService / parserOptions.project, so no untouched file's verdict can move. Full pnpm lint is CI's.
  • Not run: apps/site type-check (the five site files changed comments only), and type-checks for feat(types,plugin-designer)!: draw the data-model and process designers' read members; respell onDelete as deleteBehavior (objectui#11434, PR 2 of 3) #11454's packages after the merge (this PR touches none of their files).

Reverse verification

The prediction was written to the scratchpad before either leg ran.

BASE leg. The eight changed source files went back to 37140f4f5, and the new and edited tests ran against them. The files are the two plugin-charts sources, the examples, the layout index, the placeholders, the known-types list and the two console stub files.

  • Predicted: 19 red: ratchet 4, 7401 4, the layout retirement pin 1, containment 1, the catalog retirement pin 1 and console stubs 8. The CLI 8760 control would stay green.
  • Observed: Tests 19 failed | 80 passed (99), exactly those 19, including "refuses 24 registered bare key(s) … the pin is 20" (the count row) and the three item-3 rows red on type: 'pie-chart' and its siblings.
  • Restored: 8 blobs equal HEAD, git diff HEAD is 0 lines, and status is 0 lines.

Ablation. 'page-header' was put back into PROTOCOL_COMPONENTS with scripts/ablation-replace.mjs, run from ../objectstack. The anchor went from 1 hit to 0, and the blob from 4c56f29214af to 555e164b6888.

  • Leg 1 (source only): known-schema-types-derivation-5115 went red, "expected [ 'page-header', …(1) ] to deeply equal []" (the second entry is protocol-placeholder:page-header), and so did its byte-for-byte regen case. Result: Tests 2 failed | 11 passed (13), as predicted.
  • Leg 2 (list regenerated): the ratchet went red with "refuses 21 registered bare key(s) at type; the pin is 20", with page-header in the Refused list, and the phase-2c row and the exact-set row were red too. Result: Tests 4 failed | 21 passed (25).
  • That is one more than the 3 predicted. The namespaced pin also went red ("refuses 375 … the pin is 374") because the placeholder's twin protocol-placeholder:page-header came back with it. The direction was more red, not a reversal.
  • Restored: blob equals HEAD (4c56f29214af) and git diff HEAD is empty. A second trap restored the known-types file, and its blob f9514f0c69ba equals HEAD.

Acceptance notes

  • Capability narrowing, declared. The retired alias drew an icon and a right-hand children slot. page:header refuses properties.icon by name and a node-level children by name (both measured), so JSON authors lose both. The JSX PageHeader keeps them, and the layout changeset says so.
  • objectstack docblocks (spec ui/component-type-vocabulary.ts and lint validate-component-types.ts) cite page-header as an example of a registered kebab string-arm block. Once this lands, they cite a retired key. Carrier: objectstack. Not edited here.
  • The DOM-leak sweep no longer sweeps the pie and radar render arms, because it keeps one target per registered type and those keys are gone. The scatter arm stays swept through plugin-charts:chart.
  • The phase-2b tombstones in other packages still quote their old register(...) calls in comments. No source reader reads those files today, so they are left as they are.

Generated by Claude Code

claude added 5 commits October 2, 2026 08:57
…hart examples author chart + chartType (objectui#10859 batch 8, phase 2c)

The @object-ui/layout registration of PageHeader under page-header (and
layout:page-header) is replaced by a tombstone note, and the opt-in
PROTOCOL_COMPONENTS placeholder entry for the same spelling goes with it.
PageHeader stays an export. The layout tests, the catalog alias section,
the side-effects bundle probe and the docs are re-pointed or corrected.

pieChartExample / donutChartExample / radarChartExample now author
{ type: 'chart', chartType: 'pie' | 'donut' | 'radar' }, the last producer
of the three chart aliases.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
…rt; repin the ratchet to 20 (objectui#10859 batch 8, phase 2c)

The three chart-family aliases are unregistered with their plugin-charts
twins and CHART_TYPE_KEYWORD_FAMILIES rows, under one tombstone note. The
7401 test runs its "renders as itself" rows on chart:bar and on chart +
chartType, pins the three keys absent under both spellings, and keeps the
item-3 rows asserting each migrated example draws its family and no bar.
The console stubs, the console / cli / types stub readers and the DOM-leak
sweep follow.

Known-schema-types regenerated (9 deletions). Ratchet: REFUSED_AT_TYPE
24 to 20, NAMESPACED 379 to 374, a phase-2c row, STILL_REFUSED_10859 at
20, and the fork-2 reason rewritten with the key reading. Changesets for
plugin-charts, layout, components, cli and console, plus dated notes on
five pending entries this phase overtakes.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
…he chartType, not the example object (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

⚠️ 18 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-console-phase-2b-stubs.md

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

    BREAKING (authoring): the console no longer registers lazy stubs for scatter-chart (@object-ui/plugin-charts) or dashboard-grid (@object-ui/plugin-dashboard), which those packages retired. The metric / metric-card stubs, in register-plugins.ts and in the dev-only preview gallery, now pass skipFallback: true, like the registrations they stand in for, so only plugin-dashboard:metric / plugin-dashboard:metric-card resolve before the chunk loads.

.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/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/6872-app-shell-branding-title-jsdoc.md

  • names content/docs/guide/layout.md → content/docs/guide/layout.md — edited by this change

    Correct the AppShellBranding.title doc comment. It read "Page title suffix (sets document.title)" while useAppShellBranding assigns document.title = title wholesale — nothing is appended; the caller composes the whole string (the console passes "App label — Product name"). That comment ships in dist/index.d.ts and is the only description a consumer sees on editor hover, so a reader who followed it passed a suffix-only fragment and got a truncated title with no error. The comment now carries the same wording as content/docs/layout/app-shell.mdx, and agrees with the AppShellProps tables in the package README and content/docs/guide/layout.md. No runtime behaviour changes; the wholesale assignment and the four-surface agreement are now pinned by tests.

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

  • names renderers/placeholders.tsx → packages/components/src/renderers/placeholders.tsx — 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.

  • 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/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/7772-page-block-kanban-group-by-control.md

  • names previews/__tests__/block-config.test.ts → packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config.test.ts — edited by this change

    Run against the node those four controls produced, ObjectKanbanSchema.safeParse reported two issues, not one: groupBy "expected string, received undefined", and groupField carrying the retirement guidance verbatim. So this panel could not author a valid object-kanban node however it was filled in, and the board it produced grouped nothing with no diagnostic on any face. Both halves are now pinned against the schema itself rather than against a spelling, in previews/__tests__/block-config.test.ts — scripts/check-designer-field-key-parity.mjs judges PAYLOAD_SHAPES and does not read BLOCK_CONFIG, so nothing mechanical was watching this table.

.changeset/7926-page-node-refuses-actions.md

  • names content/docs/guide/layout.md → content/docs/guide/layout.md — edited by this change

    Scope. One key, by name; the node is NOT strict. A census over this tree read 91 authored page-tagged objects with a blind-spot reading of 8 unreadable sites, and found only actions (3 sites, all in content/docs/guide/layout.md) and breadcrumbs (1 site, its own question, untouched) surviving passthrough on a real page node — every other undeclared key belongs to a different declaration that merely spells type: 'page'. PageNodeSchema still passes unknown renderer props through.

.changeset/8278-page-tabs-item-value.md

  • names block-config.test.ts → packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config.test.ts — edited by this change

    • ComponentPropsMap['page:tabs'].safeParse returns success: false with unrecognized_keys naming key at items.0 — and 17.3.0's own message now spells the remedy out, "Did you mean key -> value?"; - PageTabsRenderer builds itemsWithValue from it.value and reads it.key nowhere, so the tab falls back to the index-derived tab-IDX; - PageTabsProps.items[].value is a real, declared schema member, which this repo's own block-config.test.ts already stated in prose.

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

  • 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.

  • names __tests__/node-slot-registered-arms-8499.test.ts → packages/types/src/__tests__/node-slot-registered-arms-8499.test.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/8760-unfulfilled-chart-stubs.md

  • 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.

  • names node-slot-registered-arms-8499.test.ts → packages/types/src/__tests__/node-slot-registered-arms-8499.test.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.

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

  • names renderers/placeholders.tsx → packages/components/src/renderers/placeholders.tsx — edited by this change

    What an unmigrated view:kanban / view:gantt node now renders depends on the host. In apps/console it renders the protocol placeholder panel, not the OBJUI-001 "Unknown component type" error: the console calls the opt-in registerPlaceholders() (@object-ui/components, renderers/placeholders.tsx) after its plugin registrations, view:kanban and view:gantt are both in that file's PROTOCOL_COMPONENTS list, and the placeholder only claims a key nothing else has taken — which, until this change, @object-ui/plugin-kanban and @object-ui/plugin-gantt had. In every other host, which does not call that bootstrap, the same node renders OBJUI-001.

  • 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/8871-page-node-refuses-breadcrumbs.md

  • names content/docs/guide/layout.md → content/docs/guide/layout.md — edited by this change

    Three author sites, all teaching passages in content/docs/guide/layout.md, and that count corrects the actions refusal's "1 site": its census reads every git-tracked JSON file, every json fence in .md/.mdx, and every TS/TSX object literal via the TypeScript AST (PR fix(types,docs): refuse actions by name on the page node, teach the shape that draws (objectui#7926) #8870), and it undercounted for two different reasons. The Schema API block declared breadcrumbs?: ArrayANGLE-BRACKETS({ label, href }) outright and its literal does carry type: 'page', but that literal sits inside a markdown typescript fence — a fence language the census's json-fence reader never visits, so it was never read at all. Best Practices §2 authored it on a fragment inside a json fence the census does read, but that fragment never writes type, so a page-tagged filter correctly excluded it. No example app, catalog fixture, template or customer document writes the key, so the refusal strands no authored document in this tree.

.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 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/retire-theme-component-schema-5489.md

  • names packages/components/src/renderers/placeholders.tsx → packages/components/src/renderers/placeholders.tsx — edited by this change

    packages/types/src/theme.ts declared a theme-manager component carrying themes[], activeTheme, allowSwitching, persistPreference and storageKey, and packages/types/src/zod/theme.zod.ts published the matching Zod object as a member of ThemeUnionSchema and therefore of AnyComponentSchema. Nothing rendered it: 'theme' appears at no ComponentRegistry.register(...) / registerLazy(...) site in packages/*/src, and in neither PROTOCOL_COMPONENTS nor PALETTE_PLACEHOLDER_BLOCKS (packages/components/src/renderers/placeholders.tsx), so it did not even resolve to a placeholder — a page declaring one got the registry's "Unknown component type" panel (OBJUI-001) instead of a theme manager. Declared-but- unenforced, removed under the maintainer ruling of 2026-08-21 (option B, executed upstream by objectstack 35ad101bc).

.changeset/retire-theme-switcher-preview-5647.md

  • names packages/components/src/renderers/placeholders.tsx → packages/components/src/renderers/placeholders.tsx — edited by this change

    packages/types/src/theme.ts declared a theme-switcher control (variant, showMode, showThemes, lightIcon, darkIcon) and a theme-preview panel (showColors, showTypography, showComponents), and packages/types/src/zod/theme.zod.ts published the matching Zod objects as the two members of ThemeUnionSchema and therefore of AnyComponentSchema. Nothing rendered either: neither literal appears at any ComponentRegistry.register(...) / registerLazy(...) site in packages/*/src (202 registered keys enumerated; positive control on the same pipeline: tooltip → 1), nor in PROTOCOL_COMPONENTS / PALETTE_PLACEHOLDER_BLOCKS (packages/components/src/renderers/placeholders.tsx), and no fixture declares either kind (control: "type": "form" → 81) — so a page declaring one got the registry's "Unknown component type" panel (OBJUI-001), never a switcher or a preview. Declared-but-unenforced, removed under the 2026-08-21 maintainer ruling (option B, executed upstream by objectstack 35ad101bc), extended to these siblings by inheritance on identical evidence (objectui#5647).

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 0e9058b95 (merge-base with origin/main): 34 file(s) changed outside .changeset/, read against 1991 pending declaration(s) that publish a body (2619 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) 3550.0 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-DNaKRdRO.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.61KB 136.72KB
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.55KB 66.16KB
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) 39.82KB 11.27KB
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.53KB 22.84KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 141.26KB 38.01KB
plugin-designer (index.js) 224.00KB 46.96KB
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: ff1cb3c5a8af692484ec96808e10832949b0bfc3
Local-runs: none

PR objectui#11457 on card objectui#10859, batch 8 phase 2c. Inputs: the card's body and all 62 comments (every comment from the batch-8 claim 5945225235 onward read in full, among them the phase-1 report 5945491717, the seat ruling 5945530142 and its amendment 5945583855, the phase-2b report 5948183744, the fork ruling 5948252391, the phase-2b ACCEPT and landing 5948265747 / 5948722028, the phase-2c report 5950551575 and the seat ACCEPT 5950575948; the earlier ones skimmed for the rulings this PR cites), the phase-2b contract record 5948430381 on PR objectui#11453; the PR body, its 44-file list (+549 / -805) and the net diff of the head against origin/main (merge-base equals the current origin/main); source at the head read with git show and git grep (the plugin-charts barrel and normalizeChartSchema.ts, the layout barrel, placeholders.tsx, the two report renderers, the DOM-leak sweep, the catalog JSON behind the page-header.mdx embed, the check-changeset-presence header, .changeset/config.json, the plugin-charts manifest); the objectstack checkout at its local main for the page-header-subtitle-alias conversion docblock, PageHeaderProps, and a grep of the four keys; the head's check-runs, polled until every run had completed. Not the dispatch order and not the dispatching seat's ACCEPT. Nothing built, run or re-run.

① Derived judgments

  1. pie-chart, donut-chart, radar-chart unregistered, each with its plugin-charts: twin and its CHART_TYPE_KEYWORD_FAMILIES row — right. At the head the three ComponentRegistry.register(...) calls are gone from packages/plugin-charts/src/index.tsx and one tombstone docblock stands in their place, describing the calls rather than quoting them (the @object-ui/types node-slot reader takes a quoted call in a comment for a live one, which is also why the phase-2b scatter-chart tombstone was reworded). The keyword table holds chart:bar alone. familyFromComponentType and the table are module-internal: the barrel exports normalizeChartSchema, NormalizedChartSchema, the two renderers, ObjectChart and chartComponents, and chartComponents only ever listed bar-chart and chart, so no public export is added, removed or re-keyed. What does move is normalizeChartSchema's answer for the three strings (no family derived), and that is the declared consequence, item 2. Grep of the head over non-test source, examples/**, the catalog, docs and skills/ for the three spellings at a type position: zero producers; the only non-test hits are tombstone and comment prose, and one component-registry.md fence that shows the reader registering a pie-chart key of their own @my-org plugin (a declared doc-snippet fragment, not this package's node, so no retired node is taught there). objectstack at its local main names none of the three. The objectui#7401 item-3 pin keeps its intent and gains a spelling pin: each example is rendered, draws pie / pie / radar marks and no bar, and must now read type: 'chart' with the matching chartType, so an example cannot drift back onto a retired key — the edit to a ruled test that the fork ruling authorised, done as it was authorised.

  2. The report path narrows for a legacy chart.type spelled one of the three — right, and declared. LegacyReportRenderer resolves schema.chart.type against the registry first and falls back to chart; with the registrations gone such a report reaches the generic ChartRenderer, whose normalizeChartSchema reads chartType, then specType, then a bare spec family, then familyFromComponentType — all four now empty for pie-chart and its siblings, so the caller's default family draws. The plugin-charts changeset states exactly that sentence and the one-line fix (give it the matching chartType), the same consequence the phase-2b record judged for scatter-chart. DatasetReportRenderer's planReportChart classifies spec ChartTypeSchema values only (pie, donut, radar, …), where the three kebab strings were already unsupported, so nothing spec-valid moves. This is a reader of an authored value, not an emitter, so the body's "0 runtime emission" holds.

  3. page-header leaves @object-ui/layout (bare and layout:page-header) and the opt-in PROTOCOL_COMPONENTS list in @object-ui/components — right, and complete. The layout barrel drops the PageHeader import and the registration; the tombstone carries the corrected reading of the objectstack conversion; the export * from './PageHeader' line is untouched, so PageHeader stays a named export (the re-pointed layout test renders it from the barrel). The placeholder removal is load-bearing, not cosmetic: registerPlaceholders() would otherwise re-register the bare key in every host that opts in (the console does), and the dev's ablation measured exactly that (derivation-5115 red, then the ratchet red at 21 with protocol-placeholder:page-header back). registerLayout() now registers four keys; README, layout.md and page-header.mdx say so and the guide's "registers four keys" sentence is held to the source by its pin. Grep of the head: zero producers of the node. The catalog example that page-header.mdx embeds (layout-page-header/basic-page-header) authors page:header; the remaining page-header hits are the docs URL slug /docs/layout/page-header, a data-testid on the app-shell PageHeader, the report-band vocabulary ReportSectionType in @object-ui/types (a different vocabulary, untouched), comments, and the retirement pins. objectstack at its local main: the conversion's fixtures and tests, two docblocks that cite the key as an example of an open-arm string, the upgrade-guide row for the conversion id, a lint comment and changelogs — no producer, and the conversion keeps renaming description on both spellings, which is harmless on a type that no longer resolves.

  4. The page-header to page:header migration narrows two capabilities for JSON authors — icon and the right-hand children slot — declared. The layout changeset says so per key and names the JSX route (PageHeader still takes icon and renders children). Read against the contract: PageHeaderProps.icon is an ADR-0087 D2 tombstone at the spec (refused by name) and children was never a PageHeaderProps member, so the JSON contract never licensed either on the canonical key; the alias was the one door, and objectui validate refused the alias at type throughout. So no validating document loses anything; a non-validating out-of-repo document that wrote the alias with an icon or buttons loses both and now draws the loud "Unknown component type" panel instead of a header — the trade the fork ruling chose with route B, with its cost named in the dev's option text. The ruling's "the capability is kept" holds for the header itself (title, subtitle, actions), and the PR says the rest plainly in the Acceptance notes. Right.

  5. KNOWN_SCHEMA_TYPES drops nine entries (four bare, five namespaced) and the console drops three stubs in both loops — right. The regenerated list matches the registrations at the head, and the derivation test's byte-for-byte regeneration case runs in the Test shards (item ③.7). chart, object-chart, bar-chart and chart:bar stay lazily registered, the stubs test adds the three keys to RETIRED, moves its control to chart:bar and expects three, and the CLI's 8760 control and the @object-ui/types node-slot reader's non-vacuity anchor move to chart:bar as well.

  6. Ratchet — right. REFUSED_AT_TYPE 24 → 20 and NAMESPACED_REFUSED_AT_TYPE 379 → 374 (five twins, protocol-placeholder:page-header among them). STILL_REFUSED_10859 holds twenty, its set-equality row holds, and the new phase-2c row pins the four keys out of the population and still refused at type, the five twins gone, and chart / page:header as lit controls that are not refused. The docblock's fork-2 sentence — the one consequence the phase-2b record left for this phase — is rewritten with the key reading. Neither pin rises.

  7. Tests re-pointed — right. page-header-authorable-keys.test.tsx keeps its path (five files and two changelogs cite it) and becomes the retirement pin with responsive-grid as the lit control under both spellings, keeping the objectui#3789 PageHeader render rows; the layout containment census has four registrations and pins that none declares the slot; the catalog test's alias section becomes a manifest retirement pin (unknown-component, with page:header as control) and its navigation-renderer halves stay; the side-effects bundle probe and the site-registrar pin look for responsive-grid; the scatter absence row's lit control is chart:bar; a new row pins the three chart keys absent under both spellings with no family derived; the DOM-leak sweep loses its three targets and its docblock counts move 181 → 178 consistently.

  8. Teaching — right. layout.md and page-header.mdx replace the "still accepted" passages with the retirement and a page:header fence, and Doc Snippet Type Check / Doc Component Type Check are green on the head; the layout README key list is corrected; the five apps/site files change comments only (confirmed hunk by hunk). No skills/ file in objectui names any of the four keys.

  9. The PR body against the tree. 44 files, +549 / -805; five new changesets; five dated notes (7401, 9910, 11044, 4761 and phase 2b's retire-scatter-chart entry) that are pure appends, each hunk starting after the entry's last existing line with the frontmatter untouched. The premise-gate, ratchet and changeset tables agree with the tree wherever the tree can answer. The "Local runs" and "Reverse verification" sections are the dev's recordings and were not re-run here.

② Semver level

  • Five minor changesets, one per released fixed-group package whose published src moved — plugin-charts, layout, components, cli, console. This is objectui's rule for a breaking change: the fixed group never declares major, 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. Three 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.
  • No entry for app-shell, types, test-support, site, the example catalog or the root scripts/ tests — correct. app-shell and types changed test files under src/__tests__/ only; test-support, @object-ui/site and @object-ui/example-* are in the ignore list, which the presence gate skips by construction; the root test files belong to no package. examples/chart-examples.ts is outside plugin-charts' files (dist, README.md, CHANGELOG.md, LICENSE), so it is unpublished, and the package's entry covers it regardless.
  • Clause-②: yes holds on the claim 5945225235, in the fork ruling 5948252391, on the PR body's third line and in every changeset: the registry accept set narrows (four bare keys and five namespaced twins stop resolving), the generated KNOWN_SCHEMA_TYPES shrinks, and normalizeChartSchema derives no family from three strings it used to. 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 five dated notes append a paragraph each and leave the frontmatter bytes untouched, so no other card's bump moves.

③ Boundary flags

  1. Dev open_questions (report 5950551575): none. The forks this PR closes are phase 2b's (report 5948183744), each on the arm the seat chose in 5948252391: fork 1 → A (migrate the three examples, re-point the 7401 pin, then retire), fork 2 → B (retire page-header now, on the corrected reading of the objectstack conversion). I read that docblock myself at objectstack's local main: "The alias here is the KEY, not the type: this entry does not rewrite page-header → page:header. That registration is objectui's to retire, on its own schedule." The seat's correction is the docblock's own text, and the live window it names is the key rename's, so waiting for the next major would change nothing about the type. Fork 3 (the ten sidebar-* primitives) is phase 2d and this head does not touch it.

  2. Dev out_of_scope_findings, each. (a) Two objectstack docblocks (ui/component-type-vocabulary.ts, lint validate-component-types.ts) cite page-header as an example of a registered open-arm string: accepted as a note — prose in another repo, the open string arm is deliberate whatever the example, and their tests use the string as an open-arm value, which stays valid; the next objectstack touch of either file refreshes the example, and no card is owed (no defect, contract violation or authoring trap). (b) sdui-parser's DASHBOARD_WIDGET_HOST_TYPES still lists dashboard-grid in both repos' copies: accepted — the phase-2b record read both copies identical and harmless (a reader of a retired key that never matches), the dev's refusal to drop it from one copy alone is the lockstep rule applied correctly, and it stays a two-repo chore for whichever side next edits that module; named here so it is not lost, not blocking. (c) The DOM-leak sweep no longer scans the pie and radar render arms: accepted, non-blocking, with the structure named — the sweep keys one row per registered type, the scatter arm already rides the single plugin-charts:chart row, so pie and radar could ride it only as second and third rows for the same type, a shape the sweep's own population rules decide; the two arms are still rendered and their marks asserted by the 7401 rows, just not leak-scanned; worth a line on the sweep's next edit, not a contract change. (d) Phase 2b's tombstones in other packages still quote their old register(...) calls in comments: accepted — the one reader that misreads such quotes reads plugin-charts, which this PR reworded; the others sit unread today, and a reader widening onto them fails red, the safe direction.

  3. Acceptance notes (PR body), each. The capability narrowing on icon / children → judged in ①.4, declared in the layout changeset. The sdui-parser item left on purpose → (b) above. The objectstack docblocks → (a). The sweep → (c). The phase-2b record's "one consequence for the next phase" — the ratchet docblock's fork-2 reason — is rewritten at this head (①.6).

  4. Deviations and shape. The two merge commits carry git's default message; the three non-merge commits carry the model-free trailer pair; the PR lands by squash and the landing seat composes the trailer pair. The PR title, body, changesets and comments 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 phase 2d. PR state at reading: draft, needs:contract-review on, auto-merge off, assignee mirrors the card, head repo equals base repo, merge state blocked (the draft flag and the checks still running when first read).

  5. 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,354 changed lines, under the 5,000 ceiling. This record is therefore the Clause-② review the landing waits on, and on PASS the owning seat readies the draft and queues it.

  6. Cross-repo. objectstack imports no export this PR removes (PageHeader stays; the chart keys are registry entries, not exports), so the Console Pin Gate is unaffected until the pin moves; the SDUI manifest regeneration at that bump is where the retired keys leave the manifest — the bump's step, not this PR's.

  7. Checks on the head. 43 check-runs, every one bound to the head and completed (polled from 11 pending down to 0; the aggregate Test run appeared last): 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, so no gate verdict weighs against this head.

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

VERDICT: PASS

Reading time: 2026-10-02T10:52Z


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 10:53
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 10:53
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit ad1785c Oct 2, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10859-batch8-phase2c branch October 2, 2026 11:09
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