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 not body. 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 body input, 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?.length alone, 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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions