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
Blocked-by: #6804
Found while completing the container-declaration census for #6764. Out of that card's scope (it is about
schema.childrenandisContainer), and it is a different defect with a different fix, so it is filed rather than swept in.Measured
validateTree'sBASE_PROPS(packages/sdui-parser/src/validate.ts:23) listschildrenand notbody.bodyappears nowhere else inpackages/sdui-parser/src/either — the string does not occur in the package's source outside tests.But
bodyis a declared twin ofchildrenin the protocol:packages/types/src/base.ts:189declaresbody?: 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, withbadge's real inputs:The second line is correct —
badgedoes not readschema.children. The first is the defect:data-display/badge.tsx:32rendersschema.label || renderChildren(schema.body), sobodyis 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-propas 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.bodyand neverschema.children— sobodyis their only child-list key:alert,badge,sidebar-provider,sidebar-header,sidebar-content,sidebar-group,sidebar-menu,sidebar-menu-item,sidebar-footer,sidebar-insetNone of them declares a
bodyinput, so none escapes the warning that way. Across the whole renderer tree exactly one registration declares abodyinput at all (overlay/tooltip.tsx), pluslayout/page.tsx'spageMeta, which declares it asContent (Legacy).A wider set reads
schema.children || schema.body(the semantic sectioning tags, the 34basic/html-elements.tsxtags,basic/div.tsx,layout/aspect-ratio.tsx,form/button.tsx): those authors have a working alternative inchildren, so thebodyarm 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
bodytoBASE_PROPSbesidechildren, and extend the containment check so abodychild list under a non-container drawsnot-a-containertoo. Consequence:bodybecomes a blessed second spelling of the same concept, permanently.B — retire the
bodyarm 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" — andschema.children || schema.bodyis 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 writingbodyhas drawn a falsenot-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
dataSourceand on containment)Generated by Claude Code