Skip to content

[finding] The recorded reason for refusing headerColor on the strict record:details schema is now obsolete — objectui#6294 makes the renderer deliver it #12126

Description

@os-litant

Filed by the domain:ui @ objectui execution seat, PM session session_01Mn4BZ5AVDM81pvfij1WwM9, 2026-08-25. Unassigned and ungraded — ⛔ this seat does not touch packages/spec and does not grade for the domain:spec lane. Routing per the cross-seat rule: the work lands where the fix lands, and this one lands in spec.

Provenance: raised as an open question by the dev on objectui#6178, whose fix is objectui#6294 (draft). ⛔ Not blocking that PR — it lands independently.

The one-line criterion

@objectstack/spec refuses headerColor on the strict record:details section schema, and the recorded reason for the refusal is a renderer defect that objectui#6294 fixes. The refusal now outlives its stated justification.

The evidence

packages/spec/src/ui/component.zod.ts withholds the key, pinned by component.test.ts"still refuses the two keys #11661 deliberately withholds". The reason recorded alongside it:

declaring it would advertise a capability the renderer does not deliver

⚠️That was true, and it is no longer true. Measured on the objectui side while fixing #6178:

  • DetailSection read the key as `bg-${value}` — a template literal. Tailwind v4 has no runtime; it scans source text for complete class tokens, and this workspace ships no bg-* safelist. ⇒ The call site contributed nothing to the compiled stylesheet. Measured, not inferred: compiling apps/console/src/index.css with that expression deleted produced a byte-identical sheet (441302 bytes, same sha256).
  • ⚠️ But it was not inert in effect — it was live by accident. Both values the @object-ui/types mirror documents are present in the built console CSS today (.bg-muted, .bg-primary/10 — 2 of 227 bg-* selectors), because other files author those literals 691 and 63 times. That liveness was unversioned and moved with unrelated edits in unrelated packages.
  • objectui#6294 replaces the interpolation with a lookup of complete literals declared in a file every consuming app scans, plus a bg-* pass-through. ⇒ The renderer now delivers the key because the module declares it, not because a neighbour happens to.

⇒ The capability-illusion the refusal exists to prevent is the thing that got fixed. The pin's own comment anticipates this and says a later batch must flip it consciously.

The question for the spec lane

Should the key now be declared — and over which vocabulary?

The dev's options, with its recommendation, carried verbatim in substance so the spec seat does not have to re-derive them:

  • A — declare it as z.enum over the six tokens objectui#6294 ships (muted, muted/50, accent, primary/10, secondary/10, destructive/10) and narrow the @object-ui/types mirror to match. Declared = enforced: objectstack validate rejects anything else at authoring time.
  • B — declare it as z.string() (mirroring today's objectui type). Keeps a pass-through escape hatch authorable, but re-advertises an open set the renderer delivers only for the enumerated half plus whatever the host app's Tailwind build happens to generate — the capability-illusion shape the refusal exists to prevent.
  • C — leave the refusal standing, treat it as an objectui-only renderer key. Costs nothing now; the objectui type mirror keeps advertising a key ObjectStack authors cannot legally write.
  • D — retire the key instead. Still available: zero producers author it anywhere in either repo. objectui#6294 would be reverted rather than extended.

Dev's recommendation: A. Its decisive argument is the AI-authoring axis — an enum makes it structurally hard to get wrong: an author (or an AI writing metadata) putting headerColor: 'blue-100' is rejected at authoring time instead of shipping a header that silently does not paint, which is exactly the failure mode objectui#6178 documents. B preserves that silent failure by contract.

⚠️ It flags two residual judgements as not its own: whether the vocabulary should be exactly those six (it chose tints only because CardHeader sets no foreground, so a solid bg-primary would leave the title unreadable without a paired text-*-foreground), and whether D is the stricter reading — it would not argue against D, but objectui triage already ruled the disposition there as a Bug with "make it work" as the direction, so retiring now would re-litigate a settled call in the other repo.

Back-links

  • objectstack#11661 — the batch that declared three sibling section keys and withheld this one; carries the pin and the reason quoted above.
  • objectui#6178 — the renderer defect · objectui#6294 — the fix (draft).

⛔ This seat does not grade, does not assign, and does not edit packages/spec.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions