Filed by the domain:spec@objectui PM seat (session session_01Jmxdo7bmeqCQHLSfmLVX9w) routing objectui#7450, whose ruling cannot be implemented in objectui. ⛔ Not claiming. Grading is the triage seat's.
Maintainer decision, 2026-09-09: option B — split across two releases. This card is release 1, and it is additive only: nothing is refused here.
Why this is a spec card and not an objectui one
objectui#7450's ruling (director batch #71, 2026-09-07, maintainer 「其他同意」) is: converge element:text on the published nine (h1–h6, body, caption, overline), with heading / subheading becoming named refusals carrying migration hints.
⚠️ The ruling's premise was false, and the correction is what routes it here. The card, its census and its triage all state that element:text's vocabulary was never declared, so nothing could refuse a wrong value. Measured, it is declared — here, at packages/spec/src/ui/component.zod.ts:1819:
variant: z.enum(['heading','subheading','body','caption']).optional().default('body')
On the installed 17.3.0 pin, ElementTextPropsSchema REFUSES h1–h6 and overline with invalid_value, and objectui's own sdui-parser validateTree already raises invalid-enum at severity ERROR for element:text + variant: h1.
⇒ The accurate statement is "the renderer swallows what the authoring gate already refuses", ⛔ not "refused by nothing".
⇒ Declaring the nine in objectui is the consumer-side widening AGENTS.md #0.1 bans, and objectui's own per-PR gate catches it. Verified independently: apps/console/src/__tests__/registry-inputs-spec-parity.test.ts emits the contract refuses the declared member(s) … at :1539 and :1800, and element:text is in its covered set (:536). Ablated end to end by the implementing seat: swapping objectui's registry inputs enum to the nine takes that gate 198 passed → 1 failed | 197 passed, naming all seven refused members.
The one-line in-repo migration is blocked by the same wall: objectui's apps/console/src/preview-samples.ts authors variant: 'subheading', which is spec-legal today, while h3 would be spec-illegal.
What release 1 does
Widen element:text.variant to the nine published values, so the enum accepts h1–h6, body, caption, overline and still accepts heading / subheading.
⛔ Nothing is retired here. No refusal, no deprecation error, no removal. This release exists so objectui can converge its renderer and its five faces on a released pin before any spelling stops working.
⚠️ The defaulting must be decided, not inherited. The current declaration carries .optional().default('body'), so a parsed element:text document materialises variant: 'body'. That interacts with objectui#6942's ruling, which deliberately does not synthesise body for an absent variant on ui:text — protecting ~690 unannotated corpus nodes. ⛔ Widening the enum must not silently change what absence means on either side; state explicitly what happens to .default('body') and why.
Sequence, so nothing is dispatched out of order
- This card — spec widens to the nine. Additive.
Clause-②: yes (a published accept set grows).
- objectui converges on the released 17.x pin: the renderer, the five faces (
elements.tsx :70 class map, :78 inline union, :85 tag map, :111 registry inputs enum, plus block-config.ts's inspector options), the two i18n rows, and the one-line preview-samples.ts migration.
- Release 2 —
heading / subheading become named refusals with migration hints, once out-of-repo authors have had a window. ⚠️ That step is blocked on the value-level retirement mechanism, which does not exist yet — filed separately, see below.
⇒ objectui#7450 closes after step 2; step 3 is its own card.
⛔ Blocked-by, and it is real
The ruling's "named refusals carrying migration hints" has no mechanism to land on. retiredKey() / ADR-0087 D2 retire a key; a sweep of packages/spec/src/shared/ surfaced no value-level equivalent. The maintainer chose the generic helper (2026-09-09), filed as its own card — release 2 waits on it. Release 1 (this card) does not.
Appetite
⛔ Falls off the back: retiring anything; changing element:text's renderer (that is objectui's, on the released pin); the ui:text side; objectui#6942's absence semantics.
Refs: objectui#7450 (the ruling and the falsification, comment 5599277303) · objectui#6942 · objectstack#12708 (the batch #70/#71 ledger) · objectui PR #8795 (the resolution pin that landed instead)
Filed by the
domain:spec@objectuiPM seat (sessionsession_01Jmxdo7bmeqCQHLSfmLVX9w) routing objectui#7450, whose ruling cannot be implemented in objectui. ⛔ Not claiming. Grading is the triage seat's.Maintainer decision, 2026-09-09: option B — split across two releases. This card is release 1, and it is additive only: nothing is refused here.
Why this is a spec card and not an objectui one
objectui#7450's ruling (director batch #71, 2026-09-07, maintainer 「其他同意」) is: converge
element:texton the published nine (h1–h6,body,caption,overline), withheading/subheadingbecoming named refusals carrying migration hints.element:text's vocabulary was never declared, so nothing could refuse a wrong value. Measured, it is declared — here, atpackages/spec/src/ui/component.zod.ts:1819:On the installed 17.3.0 pin,
ElementTextPropsSchemaREFUSESh1–h6andoverlinewithinvalid_value, and objectui's ownsdui-parservalidateTreealready raisesinvalid-enumat severity ERROR forelement:text+variant: h1.⇒ The accurate statement is "the renderer swallows what the authoring gate already refuses", ⛔ not "refused by nothing".
⇒ Declaring the nine in objectui is the consumer-side widening AGENTS.md #0.1 bans, and objectui's own per-PR gate catches it. Verified independently:
apps/console/src/__tests__/registry-inputs-spec-parity.test.tsemitsthe contract refuses the declared member(s) …at:1539and:1800, andelement:textis in its covered set (:536). Ablated end to end by the implementing seat: swapping objectui's registryinputsenum to the nine takes that gate 198 passed → 1 failed | 197 passed, naming all seven refused members.The one-line in-repo migration is blocked by the same wall: objectui's
apps/console/src/preview-samples.tsauthorsvariant: 'subheading', which is spec-legal today, whileh3would be spec-illegal.What release 1 does
Widen
element:text.variantto the nine published values, so the enum acceptsh1–h6,body,caption,overlineand still acceptsheading/subheading.⛔ Nothing is retired here. No refusal, no deprecation error, no removal. This release exists so objectui can converge its renderer and its five faces on a released pin before any spelling stops working.
.optional().default('body'), so a parsedelement:textdocument materialisesvariant: 'body'. That interacts with objectui#6942's ruling, which deliberately does not synthesisebodyfor an absentvariantonui:text— protecting ~690 unannotated corpus nodes. ⛔ Widening the enum must not silently change what absence means on either side; state explicitly what happens to.default('body')and why.Sequence, so nothing is dispatched out of order
Clause-②: yes(a published accept set grows).elements.tsx:70class map,:78inline union,:85tag map,:111registry inputs enum, plusblock-config.ts's inspector options), the two i18n rows, and the one-linepreview-samples.tsmigration.heading/subheadingbecome named refusals with migration hints, once out-of-repo authors have had a window.⇒ objectui#7450 closes after step 2; step 3 is its own card.
⛔ Blocked-by, and it is real
The ruling's "named refusals carrying migration hints" has no mechanism to land on.
retiredKey()/ ADR-0087 D2 retire a key; a sweep ofpackages/spec/src/shared/surfaced no value-level equivalent. The maintainer chose the generic helper (2026-09-09), filed as its own card — release 2 waits on it. Release 1 (this card) does not.Appetite
⛔ Falls off the back: retiring anything; changing
element:text's renderer (that is objectui's, on the released pin); theui:textside; objectui#6942's absence semantics.Refs: objectui#7450 (the ruling and the falsification, comment
5599277303) · objectui#6942 · objectstack#12708 (the batch #70/#71 ledger) · objectui PR #8795 (the resolution pin that landed instead)