Skip to content

Retire the inert register-meta key defaultChildren (#5051) - #5656

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-5051-defaultchildren-inert
Aug 22, 2026
Merged

Retire the inert register-meta key defaultChildren (#5051)#5656
os-sales merged 1 commit into
mainfrom
claude/issue-5051-defaultchildren-inert

Conversation

@os-sales

@os-sales os-sales commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Fixes #5051

Retires the register-meta key defaultChildren, which was declared in four places, produced in eleven, and read in none.

The fork was already decided — this PR executes the ruling

The card is explicitly a fork (retire the key vs. implement the consumer), and it is not a dev's to pick. It does not need picking: the maintainer ruled on it on 2026-08-19 (recorded in the issue thread, verbatim reply 「全部接受」), adopting option B — retire the key everywhere, including the row in the published plugin-author guide, per ADR-0049 enforce-or-remove. Option A (wiring children: paletteItem?.defaultChildren ?? [] into the designer) was rejected "for now; if designer default-children UX is ever product-wanted it returns as its own designed card."

That ruling is also what clears the contract-change clause: removing a declared key from @object-ui/types / @object-ui/core is a contract decision, and an authority had already made it.

Counts re-measured on the current tip, each with a positive control

A zero count is only evidence if the command is proven able to hit, so every sweep below was run through the identical pipeline as a control term known to resolve.

Surface At filing Re-measured on 7e811687a Control
Declarations 4 4 grep -cxF on the literal Registry.ts:106 line returns 1
Producers 11 11 (sidebar.tsx x10, span.tsx x1) same pipeline hits all 11
Consumers 0 0 identical pipeline finds 183 defaultProps hits, including the consumer PageDesigner.tsx:173

The control is the load-bearing part: the same command that returns zero for defaultChildren returns the twin key's consumer, so the zero is absence, not a silently-zeroed pattern. Line numbers had drifted since filing (types/base.ts 508 to 540, span.tsx 138 to 160); the counts had not.

Consumption was checked beyond the literal spelling: no bracket access (['defaultChildren']), no case-variant spelling, and the drop path destructures paletteItem field by field (defaultSize, defaultProps) with no wholesale spread that could have carried the key into a node without naming it.

What changed

  • 4 declarations: core/registry/Registry.ts, types/base.ts, types/plugin-scope.ts, types/zod/base.zod.ts — plus the SchemaNode type import in Registry.ts, which the removed line was its only remaining user.
  • 11 producers: renderers/navigation/sidebar.tsx x10, renderers/basic/span.tsx x1.
  • The published guide row in skills/objectui/guides/plugin-development.md, in this same PR as the ruling requires.
  • Two retirement pins plus a changeset.

No runtime behaviour changes in either direction. Nothing read the key before this change, so dropping a span or any of the ten sidebar types into the designer produces exactly the node it produced yesterday.

Retirement pins

One per package, both compile-time-enforced through each package's chained tsconfig.test.json:

  • packages/types — pins the zod twin and both TS twins.
  • packages/core — pins the registration surface the eleven producers were written against.

The zod half asserts a strip, not a refusal. Measured on zod 4.4.3, a plain z.object strips unknown keys rather than rejecting them, and ComponentMetaSchema has no .strict(); so an external author who still declares the key keeps a valid meta and the key is silently dropped. Asserting a rejection would have pinned a verdict this validator never emits. That "absent from output" assertion carries its own in-test control — a surviving sibling key asserted present in the same parse output through the same call, since a schema that dropped everything would otherwise satisfy it.

Verification, all on de05aed4c

Control probe on the pins, because a pin is only enforcement if it can turn red. Each leg re-declared the key, confirmed the mutation on disk by re-reading the file anchored on the injected text (not by trusting an editor exit code), then restored — with a restore trap, and the restore proven byte-identical to pristine:

=== LEG: @object-ui/types ===   post: injected-text=1 (re-read from disk)
  type-check EXIT=2   error TS2578: Unused '@ts-expect-error' directive.
  restored: byte-identical to pristine = true
=== LEG: @object-ui/core ===    post: injected-text=1 (re-read from disk)
  type-check EXIT=2   error TS2578: Unused '@ts-expect-error' directive.
  restored: byte-identical to pristine = true

An earlier attempt at this probe produced two void legs and is reported rather than buried: one wrote its log to a path containing a / from the package name, so the redirect failed and the non-zero status read back was bash's, not the type-checker's; the other used a perl replacement containing //, which terminated the regex and changed nothing. The on-disk anchor check caught the second as a no-op. Both were rerun as above.

Shipped bytes, with the type-only question settled rather than assumed: the .d.ts removals erase at runtime, and the one runtime-bearing removal in these packages is the zod mirror — dist/zod/base.zod.js now carries defaultChildren 0 times and defaultProps 1 time. Zero occurrences of the retired key across types/dist and core/dist, while the same grep still finds defaultProps in 8 dist files, so the sweep was capable of hitting.

  • Builds: @object-ui/core... and @object-ui/components^... closures, exit 0.
  • Type-check: types, core, components — all exit 0, script names echoed so a zero-match silent pass is ruled out.
  • Tests: the two new suites 6/6; the affected components superset 12 files / 157 tests, the executed file count matching the derived set.
  • Gates: check-skills-paths, check-changeset-presence, check-changeset-no-major, check-type-check-coverage, check-doc-links, check-lint-coverage, check-package-self-import, check-control-bytes — all exit 0, each captured before any pipe.
  • Lint: a full-repo eslint . --no-inline-config covered 3516 files and my 8 changed source files carry 0 errors. That run also reports 89 errors across 73 files, and those are not repo breakage: they are inline-suppressed and surface only because of --no-inline-config. The repo's actual lint is turbo run lint (per-package eslint .), which honours the suppressions — measured on one of them, RouteFader.tsx reports 1 error with the flag and 0 without. Zero overlap with this diff either way, and type-aware linting is not enabled (tseslint.configs.recommended, no project/projectService), so this diff cannot move an untouched file's verdict.

Published skills/ readings

A deletion, so both readings move down by one line.

  • Changed file plugin-development.md: 427 to 426 lines.
  • Whole published package (18 .md files under skills/): 5674 to 5673 lines.

Generated by Claude Code

…defaultChildren` (#5051)

`defaultChildren` was declared in four places, produced in eleven, and read in
none. The designer's drop path builds a node from its twin key only
(`PageDesigner.tsx`, `props: paletteItem?.defaultProps ?? {}`), so a palette item
declaring `defaultChildren` dropped an empty node and the declaration never
materialised — the declared-but-unenforced shape ADR-0049 targets.

Per the maintainer ruling of 2026-08-19 this retires the key rather than wiring
up a consumer: the 4 declarations, the 11 producers (`sidebar.tsx` x10,
`span.tsx`) and the row in the published plugin-author guide all go together.
Two retirement pins keep it out, one per package, both compile-time-enforced
through each package's chained `tsconfig.test.json`.
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 52 chunks) 3911.9 KB 3990.2 KB
Main entry chunk (gzip) 151.6 KB 350 KB
Entry file index-Cz71eksA.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 (index.js) 10.04KB 3.72KB
app-shell (runtime-config.js) 11.22KB 3.78KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 29.34KB 7.05KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 6.35KB 2.43KB
auth (index.js) 2.77KB 1.22KB
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.02KB 0.89KB
auth (useIsWorkspaceAdmin.js) 3.04KB 1.45KB
collaboration (CommentThread.js) 26.08KB 7.56KB
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) 506.21KB 113.58KB
core (index.js) 4.51KB 1.80KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 160.38KB 44.54KB
fields (index.js) 238.85KB 60.13KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.44KB 1.39KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 23.13KB 7.63KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 33.40KB 8.71KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.95KB 10.97KB
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.55KB 0.62KB
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) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useResponsiveConfig.js) 1.37KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 9.35KB 3.31KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 4.42KB 1.42KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 1.81KB 0.83KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.62KB 12.83KB
plugin-charts (index.js) 64.65KB 18.32KB
plugin-chatbot (index.js) 181.41KB 43.22KB
plugin-dashboard (index.js) 128.33KB 32.93KB
plugin-designer (index.js) 212.30KB 42.80KB
plugin-detail (index.js) 242.16KB 60.90KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 125.07KB 30.43KB
plugin-gantt (index.js) 164.10KB 39.87KB
plugin-grid (index.js) 200.79KB 54.26KB
plugin-kanban (index.js) 52.93KB 14.60KB
plugin-list (index.js) 111.74KB 27.18KB
plugin-map (index.js) 20.06KB 6.62KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 43.49KB 11.93KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.54KB 20.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.66KB 3.50KB
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) 3.77KB 1.33KB
react (SchemaRenderer.js) 43.66KB 14.77KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.33KB 0.69KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (index.js) 4.77KB 2.16KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 10.76KB 3.17KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 6.92KB 2.40KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.08KB 1.53KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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

@os-sales
os-sales marked this pull request as ready for review August 22, 2026 01:55
@os-sales
os-sales added this pull request to the merge queue Aug 22, 2026
Merged via the queue into main with commit fa429cf Aug 22, 2026
23 checks passed
@os-sales
os-sales deleted the claude/issue-5051-defaultchildren-inert branch August 22, 2026 01:56
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.

registry meta 的 defaultChildren 没有任何消费面 —— 设计器拖放只读 defaultProps,11 处声明是惰性的

2 participants