Skip to content

spec(ui): widen element:text.variant to the published nine — release 1 of 2 for the objectui#7450 convergence, additive only #17108

Description

@os-warren

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 (h1h6, 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 h1h6 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 h1h6, 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

  1. This card — spec widens to the nine. Additive. Clause-②: yes (a published accept set grows).
  2. 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.
  3. Release 2heading / 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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions