Skip to content

A component type has THREE declared surfaces that disagree (TS schema type / registry meta inputs / renderer prop reads), and nothing reconciles or enforces them #4631

Description

@yinlianghui

Measured while fixing #4626 (PR #4630). Filed unassigned. Duplicate-searched (keyword + the two renderer paths + TooltipSchema / TextSchema): no open issue covers it. This is the CLASS question #4626 raised, re-filed standalone with sharper evidence, because #4626's own framing of it turned out to be understated in one direction and wrong in another.

The class

#4626 asked whether an authored key a renderer does not read should be a publish-time rejection rather than silence. Measuring the two entries it named shows the problem is worse than "the entry used the wrong key": for a single registered type there are three places a key can be declared, and they disagree with each other. An author following any one of them can still render blank.

The three surfaces, for one component type:

  1. the TypeScript schema interface in packages/types
  2. the inputs array in the ComponentRegistry.register(...) meta
  3. what the renderer function actually reads off schema

Two measured specimens

tooltip — surface 1 contradicts 2 and 3, and following surface 1 renders blank

  • packages/types/src/overlay.ts:266 declares children: SchemaNoderequired, and it is the only slot the interface declares for the trigger. trigger is declared neither there nor on BaseSchema.
  • packages/components/src/renderers/overlay/tooltip.tsx:28 reads schema.trigger; line 31 reads schema.content || schema.body. children is read nowhere.
  • The registry meta at the same file declares trigger / content / body.

So an author who follows TooltipSchema — the type the package publishes — authors children and gets a blank tile. That is exactly what the catalog entry did, and it type-checks. The fix in PR #4630 makes the entry author trigger, which is a key TooltipSchema does not declare.

text — surface 2 declares a key surface 1 does not have, and the renderer accepts both

  • packages/types/src/layout.ts:56 declares value?: string. There is no content on TextSchema, and none on BaseSchema.
  • The registry meta declares content as required: true and defaultProps uses content.
  • packages/components/src/renderers/basic/text.tsx:35 and :40 both read schema.content || schema.value.

Both spellings work at runtime; each is "the declared one" depending on which surface you read. #4626 asserted that value is not read, and used that to explain a blank tile — measured, value IS read and the tile was not blank.

Why this is worth deciding rather than patching entry by entry

The catalog is the corpus AI authoring tools retrieve from, and this repo's stated aim is making AI-authored metadata hard to get wrong. Today the same type teaches two spellings, the published TypeScript interface can be the WRONG one, and there is no gate anywhere that compares the three. Silent-blank is the failure mode, which no red-tile sweep catches — objectui#4616's non-vacuity control found the tooltip case only because the tile drew literally nothing.

Worth deciding, in rough order of leverage:

  1. Should the three surfaces be reconciled per type, and which one is canonical? (The registry meta is the only one a designer/inspector reads; the TS interface is the only one an author's editor reads.)
  2. Should a gate assert that every inputs name exists on the type interface, and that every key a renderer reads is declared? A source-level check is plausible for the meta-vs-type half.
  3. Should an undeclared key on a registered type be rejected at publish time rather than ignored?

Refs #4626, #4616, PR #4630.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions