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
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
[a11y] The RLS USING/CHECK predicate editors render a label bound to nothing — CelPredicateField's id is optional and three call sites omit it #4533
When a call site omits id, both become undefined, so the visible label is bound to no control: the textarea has no accessible name, and the label is orphaned text.
So the RLS policy editor's USING and CHECK predicate fields — the row-filter authoring surface of a permission set — and the conditional-formatting rule editor render a label that reads correctly on screen and resolves to nothing for a screen reader. ObjectFieldInspector shows the intended shape: the prop exists and is used correctly there.
How it surfaced
Writing the wire pins for objectui#4302 I reached for the obvious selector and testing-library refused it verbatim:
TestingLibraryElementError: Found a label with the text of: USING (read filter),
however no form control was found associated to that label. Make sure you're using
the "for" attribute or "aria-labelledby" attribute correctly.
The test now selects that textarea by placeholder instead, with a comment pointing here. That is a workaround in a test, not a fix.
Why this is filed rather than fixed
Out of scope for objectui#4302, whose ruling limits the surface to the package-door slice merge and its pins. Same family as the already-fixed objectui#3994 (metadata-admin inspectors' shared field components had Label next to the control without associating them) and objectui#3341 — this is the residue those two did not reach.
Suggested shape
Pass an id at the three call sites (the RLS facet has a policy index available: rls-{i}-using / rls-{i}-check), or have CelPredicateField fall back to a generated id (React.useId()) when the prop is absent, so a call site cannot silently produce an unlabelled control. The second is the "hard to get wrong" direction — the label is rendered by the component itself, so the component can guarantee the association rather than trusting every caller to remember.
Triage: pm:queue, type: Bug. Mechanical a11y fix with the guilty call sites, the correct-shape sibling (ObjectFieldInspector), and a component-level fix direction already named (React.useId() fallback so a call site can't omit the association) — no design decision pending, same family as the already-fixed #3994/#3341.
Size/model suggestion: S, mode:subagent, model: sonnet. Prefer the component-level fallback over patching all three call sites individually — it's the "hard to get wrong" direction the filer names, and it structurally prevents a fourth call site from reintroducing this.
CLAIM — session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4533-cel-field-label-binding. Dispatching a dev agent now.
PM ruling (delegated decision authority; maintainer veto window open — record objections here): fix the CONTRACT so the accessibility hole cannot recur, not just the three call sites:
CelPredicateField generates a fallback id via React's useId() when the id prop is omitted, and uses it for BOTH Label htmlFor and Textarea id — so every mount binds its label, including future call sites that forget the prop. The explicit id prop keeps winning when passed (pin ObjectFieldInspector's four explicit-id call sites unchanged).
Whether to ALSO pass explicit ids at the three omitting call sites (PermissionAdvancedFacets RLS USING :356 / CHECK :372, ConditionalFormattingEditor :272): only if measurement shows a concrete need (e.g. stable ids asserted by existing tests); otherwise the useId fallback IS the fix — fewer moving parts.
Changeset: '@object-ui/app-shell': patch expected (CelPredicateField is module-local unless measurement says otherwise — verify via .d.ts both ways). Never major.
Mutual exclusion: ⛔ #4527-phase-2 is IN FLIGHT and owns the default-inspector family + hosts (ResourceEditPage, StudioDesignSurface, ObjectSettings/Actions/Hooks panels, ObjectValidationsPanel, Hook/Action/ViewVariant inspectors, inspector-registry types). CelPredicateField.tsx, PermissionAdvancedFacets.tsx and ConditionalFormattingEditor.tsx are NOT in its write set — but if your work needs ANY file in that list, STOP and report. Disjoint from #4541 (plugin-grid), #4553 (plugin-gantt), #4254 (plugin-kanban).
Record correction (PM, session_017Qqyix2QcnpUC9XeYVDzx3), so no future reader chases a false coordinate: this issue's table lists ConditionalFormattingEditor.tsx:272 as an omitting call site. Measured false — that mount has passed id={cf-condition-${i}} since its original commit (fba6875, #2558); the :272 reading was the opening-tag line of a multi-line JSX element whose id prop sits at :287, and four pre-existing getElementById('cf-condition-0') assertions could not have passed otherwise. The REAL third omitting site was inspectors/ConditionBuilder.tsx:227, which the table did not list. PR #4561's component-level useId fallback repairs all three real sites (RLS USING, RLS CHECK, inspectors/ConditionBuilder) without editing any call site; the corrected table is in that PR's body.
Activity
hotlong commentedon Aug 13, 2026
Triage:
pm:queue,type: Bug. Mechanical a11y fix with the guilty call sites, the correct-shape sibling (ObjectFieldInspector), and a component-level fix direction already named (React.useId()fallback so a call site can't omit the association) — no design decision pending, same family as the already-fixed #3994/#3341.Size/model suggestion: S,
mode:subagent,model: sonnet. Prefer the component-level fallback over patching all three call sites individually — it's the "hard to get wrong" direction the filer names, and it structurally prevents a fourth call site from reintroducing this.Generated by Claude Code
yinlianghui commentedon Aug 13, 2026
CLAIM — session_017Qqyix2QcnpUC9XeYVDzx3, branch
claude/issue-4533-cel-field-label-binding. Dispatching a dev agent now.PM ruling (delegated decision authority; maintainer veto window open — record objections here): fix the CONTRACT so the accessibility hole cannot recur, not just the three call sites:
CelPredicateFieldgenerates a fallback id via React'suseId()when theidprop is omitted, and uses it for BOTHLabel htmlForandTextarea id— so every mount binds its label, including future call sites that forget the prop. The explicitidprop keeps winning when passed (pin ObjectFieldInspector's four explicit-id call sites unchanged).getByLabelText('USING (read filter)')(the exact query [security] An RLS policy authored in Studio's package door is silently discarded — Save succeeds, no row filter is ever persisted #4302's dev found refused) fails on current main and passes post-fix, for all three omitting sites. Pin: explicit-id sites keep their exact ids; fix(app-shell): package-door permission save carries every editor-authorable facet (#4302) #4534's placeholder-based selection keeps working (do not edit that test — its comment already points here).Mutual exclusion: ⛔ #4527-phase-2 is IN FLIGHT and owns the default-inspector family + hosts (ResourceEditPage, StudioDesignSurface, ObjectSettings/Actions/Hooks panels, ObjectValidationsPanel, Hook/Action/ViewVariant inspectors, inspector-registry types). CelPredicateField.tsx, PermissionAdvancedFacets.tsx and ConditionalFormattingEditor.tsx are NOT in its write set — but if your work needs ANY file in that list, STOP and report. Disjoint from #4541 (plugin-grid), #4553 (plugin-gantt), #4254 (plugin-kanban).
Generated by Claude Code
Generated by Claude Code
yinlianghui commentedon Aug 13, 2026
Record correction (PM, session_017Qqyix2QcnpUC9XeYVDzx3), so no future reader chases a false coordinate: this issue's table lists ConditionalFormattingEditor.tsx:272 as an omitting call site. Measured false — that mount has passed
id={cf-condition-${i}}since its original commit (fba6875, #2558); the :272 reading was the opening-tag line of a multi-line JSX element whoseidprop sits at :287, and four pre-existing getElementById('cf-condition-0') assertions could not have passed otherwise. The REAL third omitting site was inspectors/ConditionBuilder.tsx:227, which the table did not list. PR #4561's component-level useId fallback repairs all three real sites (RLS USING, RLS CHECK, inspectors/ConditionBuilder) without editing any call site; the corrected table is in that PR's body.Generated by Claude Code
Generated by Claude Code
fix(app-shell): every CelPredicateField binds its label — useId fallb…