Skip to content

finding(sdui-parser/components): the manifest tier reports unknown-prop on body — the one child-list key 10+ registrations actually honour #6771

Description

@os-sales

Blocked-by: #6804

Found while completing the container-declaration census for #6764. Out of that card's scope (it is about schema.children and isContainer), and it is a different defect with a different fix, so it is filed rather than swept in.

Measured

validateTree's BASE_PROPS (packages/sdui-parser/src/validate.ts:23) lists children and notbody. body appears nowhere else in packages/sdui-parser/src/ either — the string does not occur in the package's source outside tests.

But body is a declared twin of children in the protocol: packages/types/src/base.ts:189 declares body?: SchemaNode | SchemaNode[], and the very next comment line says "Some components use 'children' instead of 'body'."

So a component that renders renderChildren(schema.body) publishes an authoring key the tier does not know. Measured directly against the built parser, with badge's real inputs:

badge + body -> unknown-prop: badge has no prop "body"
badge + children -> not-a-container: badge does not accept children

The second line is correct — badge does not read schema.children. The first is the defect: data-display/badge.tsx:32 renders schema.label || renderChildren(schema.body), so body is exactly the key that works, and the tier gives it the same warning it gives a typo.

This is the #6678 shape on a different key: the one spelling that resolves gets the same unknown-prop as the spellings that do nothing, on the tier built to accept AI-authored pages, where the diagnostic is the contract.

Population, from the #6764 census (runtime, over the live registry)

Of 131 bare authoring tags, 10 render schema.body and never schema.children — so body is their only child-list key:

alert, badge, sidebar-provider, sidebar-header, sidebar-content, sidebar-group, sidebar-menu, sidebar-menu-item, sidebar-footer, sidebar-inset

None of them declares a bodyinput, so none escapes the warning that way. Across the whole renderer tree exactly one registration declares a body input at all (overlay/tooltip.tsx), plus layout/page.tsx's pageMeta, which declares it as Content (Legacy).

A wider set reads schema.children || schema.body (the semantic sectioning tags, the 34 basic/html-elements.tsx tags, basic/div.tsx, layout/aspect-ratio.tsx, form/button.tsx): those authors have a working alternative in children, so the body arm is a silent second dialect rather than the only door.

Two directions, and this needs a ruling rather than a patch

They point opposite ways and the choice is a contract decision, so no recommendation is attached:

A — teach the tier the key. Add body to BASE_PROPS beside children, and extend the containment check so a body child list under a non-container draws not-a-container too. Consequence: body becomes a blessed second spelling of the same concept, permanently.

B — retire the body arm in the renderers. AGENTS.md #0.1 is explicit that a renderer reading two spellings of one concept is the lenient-fallback anti-pattern — "one strict contract beats N dialects" — and schema.children || schema.body is exactly that shape. Consequence: the 10 registrations above lose their only child-list key, so this route needs the ADR-0087-style conversion and a liveness reading on real authored metadata first.

The cheap half of the measurement is done either way: the containment check is guarded by node.children?.lengthalone, so today no author writing body has drawn a false not-a-container — the hole is silent in both directions.

Related

#6764 (the census that surfaced it) · #6678 / #6740 (the same "the tier warns on the key that works" shape on dataSource and on containment)


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:queuepriority:p1

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions