You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
showBorder on record:details sections is the same divergence #7129 just ruled on, one key over — spec REFUSES it, @object-ui/types declares it, the zod mirror declares it, the renderer honours it #7465
Found while executing the #7129 ruling (retiring DetailViewSection.hideEmpty). ⛔ Recording only — no assignee, not claimed.
#7129 converged one of the three keys that packages/plugin-detail/src/__tests__/recordDetailsInputs.spec-parity.test.ts names as RENDERER_ONLY_SECTION_KEYS. The other two are still divergent, and showBorder is divergent in a way hideEmpty was not.
Measured on the installed @objectstack/spec 17.2.0
⭐ The third row is why this is not just "#7129 again".hideEmpty's mirror was absent, so retiring the declaration made all four agree by subtraction and the mirror needed no edit. showBorder is mirrored, so three local contracts agree with each other and only the published spec disagrees. Whatever the answer is, it costs an edit somewhere that #7129's did not.
Why it is worth a decision rather than a quiet retirement
showBorder is not inert the way hideEmpty was. The renderer derives a real default from it (showBorder ?? (translatedTitle ? true : false)) and DetailSection reads it twice more (section.showBorder === false gates the flat/borderless render). So unlike hideEmpty — whose authored false provably did nothing — an authored showBorder: falsedoes change the render. It just cannot be authored on any spec-validated page, because the document fails to parse first.
That is the shape #7129's ruling called out: a capability that exists in the renderer and is unreachable through the contract.
Options (⛔ not a recommendation from a ruling — this seat is recording)
title — related but a different question, listed so it is not conflated
DetailViewSection.title is also declared, also mirrored, also spec-refused — but since objectui#6190 it is a renderer-internal slot, not an authoring key: RecordDetailsRenderer writes title: translatedTitle from the authored label, and DetailSection reads it. So "retire it" is not the same action there. Whoever picks this up should decide the two separately.
Where the existing coverage stands
recordDetailsInputs.spec-parity.test.ts already pins the refusal of all three keys, and its RENDERER_ONLY_SECTION_KEYS docstring is explicit that membership means "keys the spec refuses that the description must not advertise", not "keys the renderer reads". So the divergence is recorded today; it is not resolved. Nothing here is a regression from #7129 — that card is complete as ruled.
Found while executing the #7129 ruling (retiring
DetailViewSection.hideEmpty). ⛔ Recording only — no assignee, not claimed.#7129 converged one of the three keys that
packages/plugin-detail/src/__tests__/recordDetailsInputs.spec-parity.test.tsnames asRENDERER_ONLY_SECTION_KEYS. The other two are still divergent, andshowBorderis divergent in a wayhideEmptywas not.Measured on the installed
@objectstack/spec17.2.0columns: 2parses and the value survives — so this is about the keys, not a broken probe.hideEmpty(before #7129)showBorder(today)@objectstack/specRecordDetailsProps@object-ui/typesDetailViewSectionviews.ts)views.ts:198)zod/views.zod.tsDetailViewSectionSchemaviews.zod.ts:70)RecordDetailsRenderers.showBorder ?? (translatedTitle ? true : false))⭐ The third row is why this is not just "#7129 again".
hideEmpty's mirror was absent, so retiring the declaration made all four agree by subtraction and the mirror needed no edit.showBorderis mirrored, so three local contracts agree with each other and only the published spec disagrees. Whatever the answer is, it costs an edit somewhere that #7129's did not.Why it is worth a decision rather than a quiet retirement
showBorderis not inert the wayhideEmptywas. The renderer derives a real default from it (showBorder ?? (translatedTitle ? true : false)) andDetailSectionreads it twice more (section.showBorder === falsegates the flat/borderless render). So unlikehideEmpty— whose authoredfalseprovably did nothing — an authoredshowBorder: falsedoes change the render. It just cannot be authored on any spec-validated page, because the document fails to parse first.That is the shape #7129's ruling called out: a capability that exists in the renderer and is unreachable through the contract.
Options (⛔ not a recommendation from a ruling — this seat is recording)
showBorderin the spec'srecord:detailssection object. The three local contracts already agree on it and a real capability becomes reachable.hideEmptyonrecord:detailssections: the spec REFUSES the key,@object-ui/typesdeclares it, the zod mirror omits it, and the renderer honours it — plushideEmpty: falseis not an override #7129's "the platform decides, the app does not author" direction; also cross-repo (objectstack).hideEmptyonrecord:detailssections: the spec REFUSES the key,@object-ui/typesdeclares it, the zod mirror omits it, and the renderer honours it — plushideEmpty: falseis not an override #7129 did forhideEmpty: drop the declaration, the mirror member and the reads, and let the current heading-derived default (border iff the section has a heading) be the whole contract.hideEmptyonrecord:detailssections: the spec REFUSES the key,@object-ui/typesdeclares it, the zod mirror omits it, and the renderer honours it — plushideEmpty: falseis not an override #7129 this removes a working capability, so it needs the borderless-flat render's callers checked first.hideEmptyonrecord:detailssections: the spec REFUSES the key,@object-ui/typesdeclares it, the zod mirror omits it, and the renderer honours it — plushideEmpty: falseis not an override #7129 recorded: a key declared in three contracts and refused by a fourth is the shape that produces confident wrong code.title— related but a different question, listed so it is not conflatedDetailViewSection.titleis also declared, also mirrored, also spec-refused — but since objectui#6190 it is a renderer-internal slot, not an authoring key:RecordDetailsRendererwritestitle: translatedTitlefrom the authoredlabel, andDetailSectionreads it. So "retire it" is not the same action there. Whoever picks this up should decide the two separately.Where the existing coverage stands
recordDetailsInputs.spec-parity.test.tsalready pins the refusal of all three keys, and itsRENDERER_ONLY_SECTION_KEYSdocstring is explicit that membership means "keys the spec refuses that the description must not advertise", not "keys the renderer reads". So the divergence is recorded today; it is not resolved. Nothing here is a regression from #7129 — that card is complete as ruled.Related
hideEmptyonrecord:detailssections: the spec REFUSES the key,@object-ui/typesdeclares it, the zod mirror omits it, and the renderer honours it — plushideEmpty: falseis not an override #7129 — the ruled sibling (hideEmpty), landed as PR feat(types): retireDetailViewSection.hideEmpty— the auto-hide heuristic is the whole contract #7464. Not reopened by this.record:detailsregistration comment says the spec STRIPS undeclared section keys — measured, it REFUSES them, and the same comment block already says so two sentences earlier #7127 — therecord:detailsregistration comment says the spec "STRIPS" undeclared section keys; measured, it refuses them. Same measurement, different artefact.