Skip to content

docs: three visibleWhen binding claims are now wrong in the other direction — objectui bound current_user on form section/field predicates (objectui#6010) #11740

Description

@yinlianghui

Filed unassigned, no domain:* — triage owns grading and routing.

Blocked-by: ✅ discharged — objectstack-ai/objectui#6010 landed as objectui PR #6037 (fix(components): bind current_user on form section/field visibleWhen, merged 2026-08-24). This card is the documentation half that card's own dispatch reserved for the accepting seat, filed at landing time as instructed and deliberately not carried as a rider on the objectui PR.

Filed by the objectui domain:ui PM seat (session session_01CSoz9uGhaaSgiq3hshtN7L, R38).

What changed upstream

Until objectui#6010, form section/fieldvisibleWhen predicates bound only record and previouscurrent_user was unbound, so a predicate naming it faulted open and showed the field to everyone. Page components, app/nav visible, and per-option visibleWhen all bound it. #11034 split this repo's binding table precisely to document that asymmetry, which was the honest thing to do at the time.

objectui#6010 removed the asymmetry. All five authored-predicate call sites in the form renderer now receive the predicate scope — the three resolveFieldRuleState calls plus the two visibleOnevalFieldPredicate calls (ADR-0089 D2 folds visibleOn into visibleWhen at parse, so binding one and not the other would have reproduced the defect one spelling over). It was graded a declared≠enforced restoration against ADR-0089 D1, which rules verbatim: "runtime record surfaces bind record + current_user; metadata-editing forms bind data."

⚠️ So the rows added by #11034 are now wrong in the opposite direction: they document an asymmetry that no longer exists.

Three corrections, in two files

The objectui dev who implemented #6010 searched this repo and found the claim in two places, not one. ⚠️ A card naming only layout-dsl.mdx would leave the second live — which is the same half-fix problem, one layer up.

1. content/docs/protocol/objectui/layout-dsl.mdx — the binding table at :831-832 and the prose at :866. These are the rows #11034 split. Form section/field predicates now bind current_user like every other runtime record surface.

2. content/docs/ui/views.mdx:433 carries the same claim independently, verbatim:

"runtime forms bind record (+ previous, parent) — not current_user, which is unbound at field level and would fault the predicate open"

⚠️ This one is not a cross-reference to (1); it is a second copy that has to be corrected on its own.

3. content/docs/protocol/objectui/layout-dsl.mdx:862-863 — a bare-string authoring trap, adjacent but distinct. This is not about the binding; it is about the dialect, and it is worth fixing while the page is open because the example on it is the exact shape that breaks:

  • the objectui form renderer treats a bare string predicate as CEL (fieldRules.tstoExpression defaults dialect to 'cel');
  • SchemaRenderer.evaluateCondition routes bare strings to the legacy JS evaluator, which has no in operator and rejects it — measured verbatim: Unexpected token "i" at position 16 — and then fails open;
  • this is deliberate and documented (objectui#2661: "Bare strings and template forms stay on the legacy path (back-compat deprecation window); only an explicit { dialect: cel } envelope is rerouted"), and spec parse emits the CEL envelope for authored metadata, so production is unaffected;
  • ⚠️ but layout-dsl.mdx:862-863 shows exactly that bare string, carrying the CEL membership operator, on a PageComponent / app-nav entry. A reader copying it authors a predicate that is not portable across surfaces.

✅ The residual is therefore a docs problem, not a code one — recorded as measured behaviour rather than filed as a defect. It caught the objectui dev's first pin run, which is how it surfaced.

Suggested scope

Correct (1) and (2) to state the current binding, and re-author the example in (3) into the canonical { dialect: 'cel' } envelope (or drop the membership operator from the bare-string example). ⛔ Do not re-merge the table rows #11034 split without checking whether any other asymmetry it documents is still live — the split may still be earning its keep for a different pair.

Pointers

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions