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
Follow-up to implement the decision in ADR-0089 (docs/adr/0089-unify-visibility-predicate-naming.md), merged in #2641. The ADR is the design decision only — no code has changed yet. This issue tracks the implementation.
Problem (recap)
The same "show only when the CEL predicate is TRUE" concept is spelled three ways by layer, and zod's default strip mode makes a mis-layered key vanish silently:
Layer
Key today
Location
Data field / field option
visibleWhen
packages/spec/src/data/field.zod.ts:592, 108
View form section / field
visibleOn
packages/spec/src/ui/view.zod.ts:762, 781
Page component
visibility
packages/spec/src/ui/page.zod.ts:109
Canonical target is visibleWhen (aligns with the existing readonlyWhen/requiredWhen family and the conditionalRequired → requiredWhen precedent).
Tasks
D1 — canonical visibleWhen. Accept visibleWhen on view form sections/fields (view.zod.ts) and page components (page.zod.ts), matching the data-field semantics. Document the per-layer binding root (runtime surfaces bind record + current_user; metadata-editing forms bind data).
D2 — alias + parse-time normalization. Mark visibleOn / visibility@deprecated; normalize to visibleWhen in parse() (fold visibleOn ?? visibility into visibleWhen when the canonical key is absent), mirroring the conditionalRequired/requiredWhen pattern in field.zod.ts:594-598. Register the rename in the deprecation / spec-changes.json registry per ADR-0087.
D3a — .strict(). Tighten the relevant object schemas so a mis-layered / stale-alias visibility key is a parse error, not a silent strip (ADR-0049 enforce-or-remove, ADR-0078 no-silently-inert). Sweep the monorepo + example apps before flipping strict on.
D3b — lint rule. Add a @objectstack/lint rule flagging (a) a deprecated alias in freshly authored source (autofix → visibleWhen), and (b) a predicate whose binding root mismatches its layer (data. in a runtime form predicate, or record. in a metadata form predicate).
Codemod first-party sources.packages/ + examples/: visibleOn (~13 files) / visibility (~34 files) → visibleWhen. Update content/docs/** and the objectstack-ui / objectstack-data skills (including the layer→binding-root table).
Renderer reads. Confirm ObjectUI form + page renderers read the normalized visibleWhen.
Deprecation window then removal. Keep aliases for the standard window; remove in a future major.
Out of scope
Boolean visible (Tab on/off, view.zod.ts:276) — a static flag, not a predicate; keeps its name and type per ADR-0089 D4.
hidden (field boolean) and visibleFields (gallery card array) — unrelated.
Follow-up to implement the decision in ADR-0089 (
docs/adr/0089-unify-visibility-predicate-naming.md), merged in #2641. The ADR is the design decision only — no code has changed yet. This issue tracks the implementation.Problem (recap)
The same "show only when the CEL predicate is TRUE" concept is spelled three ways by layer, and zod's default strip mode makes a mis-layered key vanish silently:
visibleWhenpackages/spec/src/data/field.zod.ts:592, 108visibleOnpackages/spec/src/ui/view.zod.ts:762, 781visibilitypackages/spec/src/ui/page.zod.ts:109Canonical target is
visibleWhen(aligns with the existingreadonlyWhen/requiredWhenfamily and theconditionalRequired → requiredWhenprecedent).Tasks
visibleWhen. AcceptvisibleWhenon view form sections/fields (view.zod.ts) and page components (page.zod.ts), matching the data-field semantics. Document the per-layer binding root (runtime surfaces bindrecord+current_user; metadata-editing forms binddata).visibleOn/visibility@deprecated; normalize tovisibleWheninparse()(foldvisibleOn ?? visibilityintovisibleWhenwhen the canonical key is absent), mirroring theconditionalRequired/requiredWhenpattern infield.zod.ts:594-598. Register the rename in the deprecation /spec-changes.jsonregistry per ADR-0087..strict(). Tighten the relevant object schemas so a mis-layered / stale-alias visibility key is a parse error, not a silent strip (ADR-0049 enforce-or-remove, ADR-0078 no-silently-inert). Sweep the monorepo + example apps before flipping strict on.@objectstack/lintrule flagging (a) a deprecated alias in freshly authored source (autofix →visibleWhen), and (b) a predicate whose binding root mismatches its layer (data.in a runtime form predicate, orrecord.in a metadata form predicate).packages/+examples/:visibleOn(~13 files) /visibility(~34 files) →visibleWhen. Updatecontent/docs/**and theobjectstack-ui/objectstack-dataskills (including the layer→binding-root table).visibleWhen.Out of scope
visible(Tab on/off,view.zod.ts:276) — a static flag, not a predicate; keeps its name and type per ADR-0089 D4.hidden(field boolean) andvisibleFields(gallery card array) — unrelated.References
docs/adr/0089-unify-visibility-predicate-naming.md) · merged in docs(adr): ADR-0089 — unify conditional-visibility predicate undervisibleWhen#2641conditionalRequired → requiredWhenresolution infield.zod.ts+ coalesce inpackages/objectql/src/validation/rule-validator.ts:378visibleOn)