retire(detail): remove the record:details layout input and its dead renderer branch - #4245
Merged
Merged
Conversation
…ad renderer branch (#3818) `record:details` published `layout: enum ['auto','custom']` with `defaultValue: 'auto'`, described as the detail-body selector. It never selected anything: the renderer's only `schema.layout` read tested `'inline' | 'compact'` — values the schema never permitted — so both legal values took the same branch and resolved to `'vertical'`. @objectstack/spec 17.0.0 removed the property (objectstack#6946, ADR-0087 D2) and the pinned 17.0.0-rc.6 already rejects it on parse. This completes the objectui half per the 2026-08-09 maintainer ruling on #3818: - delete the `layout` input declaration and the prose that taught it - delete the dead `inline`/`compact` branch; the synthesized `layout` is now the constant it always resolved to - pin the retirement: the spec rejects the key (path + code + migration message), the manifest publishes no `layout` input, no description teaches it, and the renderer source carries no `schema.layout` read - pin the real contract as the positive control — `sections` presence decides the body, both directions plus the empty-array boundary Also makes the derived "declares no top-level input the spec does not accept" gate tombstone-aware. A D2 tombstone stays in the spec's `.shape` as a `z.never()`, so a retired key still answers a key-presence check — which is why this input survived the rc.6 bump with every derived gate green. The `@object-ui/types` mirror's `layout` key stays attached to #2231/#2890 per the ruling: it still has a reader (`types/src/__tests__/p1-spec-alignment.test.ts`). Fixes #3818 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
…on (#3818) CI shard 2/4 went red on the repo-wide gate in `apps/console/src/__tests__/registry-inputs-spec-parity.test.ts`: record:details publishes every top-level key its spec props schema declares AssertionError: expected [ 'layout' ] to deeply equal [] Same tombstone blindness this PR fixed in the plugin-detail parity file, in the MIRROR direction. `specTopLevelKeys` reads raw `Object.keys(shape)`; an ADR-0087 D2 retirement replaces the member with `z.never().optional()` rather than deleting it, so the retired `layout` still reads as "spec-declared" and the reverse direction demands the input this PR deliberately removed. Parked as an `UNPUBLISHED_EXEMPTIONS` entry, the convention this file already established for the four other D2 tombstones (`element:record_picker`'s trio and `page:card.body`), each of which cites objectui#3809 — the open card that owns narrowing `specTopLevelKeys` to non-tombstone members. Fixing it here instead would do #3809's work and strand those four entries as stale. The entry's comment records why this one is NOT more stale-pin cover: the four above are still published and waiting for a pin bump, whereas this key is already withdrawn and the tombstone is live at rc.6 — the reverse direction demanding a key the forward direction forbids. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3818
Completes the objectui half of the
record:detailslayoutretirement, per the maintainer ruling of 2026-08-09 on this card (removal) and the upstream retirement in objectstack#6946 (ADR-0087 D2), now active on the pinned@objectstack/spec@17.0.0-rc.6.What was wrong
record:detailspublished a body selector that never selected anything:packages/plugin-detail/src/index.tsxdeclared{ name: 'layout', type: 'enum', enum: ['auto','custom'], defaultValue: 'auto' }, described as "auto uses the object highlightFields; custom uses explicit sections".renderers/record-details.tsx:103-104) testedschema.layout === 'inline' || schema.layout === 'compact'— two values the schema never permitted — so both legal values fell through the same ternary to'vertical'.autoandcustomtherefore behaved identically, in both directions and with zero diagnostics:'auto'plus explicit sections still rendered the sections, and'custom'with no sections silently fell back to the flat body. Because the input carried adefaultValue, this was the manifest actively offering the key, not stale prose.Premise check
All four points verified on this branch's tip before implementing:
index.tsxstill declares the inputlayout17.0.0-rc.6,path: ["layout"],code: invalid_type,expected: "never", with the ADR-0087 migration messagerecordDetailsInputs.spec-parity.test.tsis layout-free; treated as control, not redoneChanges
layoutinput declaration, and the two pieces of prose that outlived it: the block comment'slayout: 'custom'clause and thesectionsdescription's closing "Required when layout is 'custom'". A neighbouring description would otherwise have kept teaching the key after the input was gone.inline/compactbranch. The const collapsed to the constant it always resolved to, so it is inlined aslayout: 'vertical'with a comment recording why it is constant by contract.Pins
Negative, mirroring the #4239/#4226 shapes — in
recordDetailsInputs.spec-parity.test.ts:layoutfor all four values (auto,custom,inline,compact), asserted as a full envelope —path+code+ the named migration message, not a bare "it failed";layoutinput (non-emptyinputs()asserted FIRST, so the absence cannot pass vacuously);schema.layoutread.Positive control — new
recordDetailsBodySource.test.tsx, pinning the contract that was doing the work all along and is now the only declared one:sectionspresence decides the body. Sections authored renders the groups and excludes a field outside them; sections absent renders the flat body; and the empty-array boundary behaves as absence rather than blanking the page.The tombstone blind spot — worth the reviewer's attention, it bit twice in opposite directions
An ADR-0087 D2 tombstone stays IN the spec's
.shapeas az.never(). Measured here:Every gate that asks "is this key in the shape" therefore reads a retired key as live. This PR hit both sides of that:
layoutis declared" and stayed green with the retired input still published — which is why this drift survived the rc.6 pin bump undetected. That gate now filters tombstoned members out.apps/console/src/__tests__/registry-inputs-spec-parity.test.tsasserts the mirror image — every spec-declared key must be published — so deleting the input made it demand the key back:Same root cause, opposite sign. Fixed the way that file already established for its four other D2 tombstones (
element:record_picker's trio andpage:card.body): anUNPUBLISHED_EXEMPTIONSentry citing #3809, the open card that owns narrowingspecTopLevelKeysrepo-wide. Narrowing it here instead would do #3809's work and strand those four entries as stale — and the entry's comment records why this one is not more stale-pin cover: the other four are still published awaiting a pin bump, whereas this key is already withdrawn and its tombstone is live at rc.6.Reverse verification
Direction predicted before running: reverting both deletions should turn 4 assertions red, and the 3 positive-control tests should stay green. Confirmed exactly:
The first red is the proof that the tombstone-awareness fix is load-bearing: before it, that gate was green with the input published.
The positive-control tests staying green is deliberate, and is recorded in the test file rather than papered over. The deleted branch fed
synthesized.layout, andDetailViewnever readslayoutat all — no read site, no schema spread. The branch was dead twice over (retired vocabulary AND ignored consumer), so restoring it changes no rendered output. A DOM-equality "authoringlayoutchanges nothing" assertion would therefore have stayed green through the exact regression it appeared to guard, so it was not written; the read point is pinned where it can actually go red.Restored afterwards, back to 16/16 green.
Mirror verdict: stays attached
The ruling attached the
@object-ui/typesmirror drift to #2231/#2890, and the measurement agrees.RecordDetailsComponentProps.layout?: 'stacked' | 'inline' | 'compact'still has a reader after the renderer read is deleted —packages/types/src/__tests__/p1-spec-alignment.test.tsconstructslayout: 'stacked'and asserts it — so it is not dead-code cleanup that can ride along here. Left in place, noted on #2890.Verification
pnpm --filter '@object-ui/plugin-detail^...' build(dependency closure first, in a fresh worktree)pnpm --filter '@object-ui/plugin-detail' test— 70 files, 626 tests, all passing (main was1 failed | 618 passedbefore PR fix(i18n): render I18nLabel objects at the 13 remaining sites #4208 fixed the fixture half; 619 + 7 new = 626)pnpm --filter '@object-ui/plugin-detail' type-check— green (bothtsc --noEmitand the typetests project)pnpm exec vitest run apps/console/src/__tests__/registry-inputs-spec-parity.test.ts— 51/51 green after the exemption entryeslinton the changed files — 0 errors (59 pre-existingno-explicit-anywarnings)pnpm check:control-bytes— OK, 3948 filespnpm check:spec-symbols— green, unchangedpnpm changeset:check— greendependabotandTest (coverage), both by design).Straggler sweep
Repo-wide grep for the retired vocabulary: no doc row lists the
layoutinput (content/docs/guide/react-pages.mdmentionsrecord:detailsbut not this key), and no generated manifest artifact is tracked in git —sdui.manifest.json/sdui-intrinsics.d.tsare written at build time. Every remaining occurrence is deliberate historical narrative in the test files, plus the immutableCHANGELOG.md.Changeset:
@object-ui/plugin-detailpatch. Nothing that worked stops working — the key is already unauthorable at the contract, andos migrate meta --from 16rewrites existing sources — so this is removing a false advertisement rather than a capability. Flagging the level for the bump-policy call: AGENTS.md allowsminorfor objectui's own breaking changes and forbidsmajor;patchis per dispatch, and easy to raise if you read a published-input removal as breaking.Generated by Claude Code