Commit b36a6d7
docs(protocol): teach position-gated visibility with the binding it actually has (#11413)
The `visibleWhen` example taught `user.hasRole('admin')`. `hasRole` is not a CEL
function: it is in no stdlib registry and on no contract, so the predicate faults
and — visibility being fail-open — the gate it illustrates shows the element to
everyone. Worst possible direction for the feature being demonstrated.
Measured before rewriting, since the answer decides the wording:
- A `user.*` binding DOES exist. ADR-0068 D1 makes `current_user` canonical with
`user` / `ctx.user` aliases, and objectui's ExpressionProvider binds all of
them. What does not exist is `hasRole` — `EvalUser` carries `positions:
string[]` as data, not methods, and `CEL_STDLIB_FUNCTIONS` (30 entries, drift-
guarded) has no such call.
- The canonical membership test is `'<name>' in current_user.positions`, live in
`content/docs/ui/pages.mdx` and in the showcase example app.
- But `current_user` does not reach every layer. Page components, app/nav entries
and per-option predicates bind it; form sections and fields do not — all three
`resolveFieldRuleState` call sites in objectui's form renderer pass `undefined`
for the scope argument, so those predicates see `record` and `previous` only.
The example's own label was "on a FormSection / FormField" — the one layer with
no user binding at all. So swapping `hasRole` for `positions` in place would have
moved it from faulting on a missing method to faulting on an unbound root, still
fail-open, still shown to everyone.
Instead: the example keeps `record`-only on the form layer, the binding table
splits the row that claimed forms bind `current_user`, and a new subsection
teaches the supported spelling, names the layers it works on, and points anything
that must be enforced at the permission layer rather than at a visibility gate.
Vocabulary follows ADR-0090 D3 (`position`, not the retired word), which
`check:role-word` enforces.
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
Co-authored-by: Claude <noreply@anthropic.com>1 parent 35c1ca3 commit b36a6d7
1 file changed
Lines changed: 38 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
817 | 817 | | |
818 | 818 | | |
819 | 819 | | |
820 | | - | |
| 820 | + | |
821 | 821 | | |
822 | 822 | | |
823 | | - | |
824 | | - | |
| 823 | + | |
| 824 | + | |
825 | 825 | | |
826 | 826 | | |
827 | 827 | | |
828 | 828 | | |
829 | 829 | | |
830 | 830 | | |
831 | | - | |
| 831 | + | |
| 832 | + | |
832 | 833 | | |
833 | 834 | | |
834 | 835 | | |
| |||
846 | 847 | | |
847 | 848 | | |
848 | 849 | | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
849 | 883 | | |
850 | 884 | | |
851 | 885 | | |
| |||
0 commit comments