Found while correcting BaseSchema.hidden's JSDoc for #7088. Filed unassigned and out of that card's scope: #7088's ruling is comment-level with Clause ② no, and this is a change to the declared type surface, which is the kind of thing #4580 needed a ruling for.
The claim
packages/types/src/base.ts declares:
content/docs/api/schema-reference.md states the same thing as behaviour:
| hidden | boolean | Inverse of visible. Boolean only — unlike visible, this key takes no expression. |
What the renderer does
SchemaRenderer.tsx's shouldHide chain does not read this key as a boolean either. It calls the same evaluator every other leg calls:
if(hasDeclaredPredicate(newSchema.hidden)){returnevaluateVisibilityPredicate(newSchema.hidden,'hidden');}and predicate strings on hidden are already pinned as working, in packages/react/src/__tests__/SchemaRenderer.hiddenDeclaredGate.test.tsx:
it('an expression-valued hidden keeps its verdict, both ways') — hidden: '${data.status === "draft"}' hides, hidden: '${data.published}' does not;it('a non-empty CEL envelope keeps its verdict, both ways') — hidden: { dialect: 'cel', source: 'true' } hides.
So the declaration under-reports a shipped, tested capability, and the docs row states the under-report as a fact about behaviour.
Why this is the same defect twice already fixed next door
visible carried exactly this asymmetry until objectui#4581 widened it to boolean | string, on the evidence that the renderer evaluates rather than reads it. disabled carried it until #4580 ruling Q3-A widened it on the identical evidence. base.ts's own JSDoc for both keys now records that reasoning in full — and both blocks note the sibling *On key exists for the same reason, which is the argument that was NOT taken to mean the base key should stay boolean.
hidden is the third key on that evaluated path and the only one still declared boolean-only, with hiddenOn as its sibling. The two earlier widenings also record that fixtures had been casting past the declaration; the pins above pass arbitrary values through a Record cast, so the same pressure is present here.
Not decided here
Whether to widen hidden to boolean | string (with the zod mirror and the docs row following), or to keep the narrow declaration deliberately and correct the docs row to describe the shipped behaviour instead. The two produce different diffs and different published surfaces:
Either way the declaration, the docs row and the pins should end up saying one thing; today they say two.
Refs #7088 · #4581 · #4580 · #3955.
Generated by Claude Code
Generated by Claude Code
Found while correcting
BaseSchema.hidden's JSDoc for #7088. Filed unassigned and out of that card's scope: #7088's ruling is comment-level with Clause ②no, and this is a change to the declared type surface, which is the kind of thing #4580 needed a ruling for.The claim
packages/types/src/base.tsdeclares:content/docs/api/schema-reference.mdstates the same thing as behaviour:What the renderer does
SchemaRenderer.tsx'sshouldHidechain does not read this key as a boolean either. It calls the same evaluator every other leg calls:and predicate strings on
hiddenare already pinned as working, inpackages/react/src/__tests__/SchemaRenderer.hiddenDeclaredGate.test.tsx:it('an expression-valuedhiddenkeeps its verdict, both ways')—hidden: '${data.status === "draft"}'hides,hidden: '${data.published}'does not;it('a non-empty CEL envelope keeps its verdict, both ways')—hidden: { dialect: 'cel', source: 'true' }hides.So the declaration under-reports a shipped, tested capability, and the docs row states the under-report as a fact about behaviour.
Why this is the same defect twice already fixed next door
visiblecarried exactly this asymmetry until objectui#4581 widened it toboolean | string, on the evidence that the renderer evaluates rather than reads it.disabledcarried it until #4580 ruling Q3-A widened it on the identical evidence.base.ts's own JSDoc for both keys now records that reasoning in full — and both blocks note the sibling*Onkey exists for the same reason, which is the argument that was NOT taken to mean the base key should stay boolean.hiddenis the third key on that evaluated path and the only one still declared boolean-only, withhiddenOnas its sibling. The two earlier widenings also record that fixtures had been casting past the declaration; the pins above pass arbitrary values through aRecordcast, so the same pressure is present here.Not decided here
Whether to widen
hiddentoboolean | string(with the zod mirror and the docs row following), or to keep the narrow declaration deliberately and correct the docs row to describe the shipped behaviour instead. The two produce different diffs and different published surfaces:hiddenOn) already.hiddenOnas the declared expression spelling and the evaluator's tolerance as incidental; then the docs sentence "this key takes no expression" needs rewording, since it is false of the renderer, and the pins that exercise expression-valuedhiddenare pinning tolerance rather than contract.Either way the declaration, the docs row and the pins should end up saying one thing; today they say two.
Refs #7088 · #4581 · #4580 · #3955.
Generated by Claude Code
Generated by Claude Code