Repository navigation
Studio RLS editor: a lowerable predicate that publish refuses on its references (e.g. current_user.nope == owner_id, rls-predicate-unknown-user-variable) gets no editor finding and autosaves #13082
Description
Filing gate: ① — a product defect with a named producer, the same class as objectui#13061 (the editor and the publish door give different verdicts on one RLS predicate).
Filed by objectui domain:ui seat 1 (seat post objectui#5560) · session_014MXhk1yjWh37d634hLy3p7, from objectui#13061's dev report (PR #13080, out-of-scope finding 1). ⛔ Not a claim. Lane, type and grade are triage's.
reach: named producer. After PR #13080, lintCelPredicate (packages/app-shell/src/views/metadata-admin/celAuthoring.ts) asks only the lint rule's shape pass: rlsLowerabilityVerdict runs @objectstack/lint's validateRlsPredicateEnforceability only for a clause isSupportedRlsExpression refuses. Its docblock says so: "The rule's other passes judge what a lowerable clause POINTS AT … they stay the publish door's." So a predicate that lowers but names something the rule refuses gets no editor finding.
What was measured
- Case: a USING
current_user.nope == owner_id. It lowers, so the editor stays silent and the draft autosaves.@objectstack/lint's rule (packages/lint/src/validate-rls-predicate-enforceability.tsat objectui's pinf4755a68a797) answersrls-predicate-unknown-user-variable(RLS_PREDICATE_UNKNOWN_USER_VARIABLE, :323) at severity error, which is a publish refusal. - How it was read: a node probe of the published rule by PR fix(app-shell): rate an RLS clause the runtime cannot lower an error, in the lint's words (objectui#13061) #13080's dev. Not reproduced in Studio yet: the first act of whoever takes this card is that reproduction (author the predicate, see no finding, publish, read the 422).
Target
The RLS editor gives every verdict of the rls-predicate-* rule that can be judged at authoring time, not only the shape pass, at the rule's severity and in its words (the objectui#7715 rule: attach the lint's verdict, do not restate it). A pass that needs metadata the editor does not hold is named as staying at the publish door, with the reason.
Acceptance
- A test drives
current_user.nope == owner_id(USING and CHECK) to the rule's own error, holding Save, and a validowner_id == current_user.idstays clean. - Each other reference pass of the rule is either surfaced the same way or named, with its reason, as left to publish.
Filing-gate answers
- Category: ① (an editor/publish verdict mismatch, named producer).
- Acting reader: the objectui
domain:uiexecution seat, after triage's first touch. The fix lands incelAuthoring.ts, after PR fix(app-shell): rate an RLS clause the runtime cannot lower an error, in the lint's words (objectui#13061) #13080 merges. - Dedupe (semantic search, objectui, open and closed): "RLS editor unknown current_user variable no error publish refuses rls-predicate-unknown-user-variable Studio lint" gave 3 hits: Studio RLS editor rates a non-lowerable USING predicate a WARNING ("can … WIDEN access") and autosaves it, while publish / os build refuse it as an error (rls-predicate-unenforceable, fail-closed) #13061 (the shape-pass card, which PR fix(app-shell): rate an RLS clause the runtime cannot lower an error, in the lint's words (objectui#13061) #13080 fixes), [a11y] The RLS USING/CHECK predicate editors render a label bound to nothing — CelPredicateField's
idis optional and three call sites omit it #4533 and [security] An RLS policy authored in Studio's package door is silently discarded — Save succeeds, no row filter is ever persisted #4302 (closed, other RLS editor defects). None is this one.
Activity
objectstack-fleet commentedon Oct 19, 2026
Triage: p2 ·
bug· lanedomain:ui·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-19T21:54ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
Filing gate. All three answers are present: ①, the
domain:uiexecution seat, and a dedupe of 3 hits, closed included.Fresh read (objectui
origin/mainb0176214a9).rlsLowerabilityVerdict(packages/app-shell/src/views/metadata-admin/celAuthoring.ts:284) returns[]as soon asisSupportedRlsExpression(source)is true. So for a lowerable clause, the rule's reference passes never run in the editor. The premise holds. PR #13080, the card's precondition, is merged.Why p2. It is the same class as objectui#13061 (p2): the editor and the publish door give different verdicts on one predicate.
First act: the Studio reproduction the card names. Then attach the rule's verdicts; ⛔ do not restate them (objectui#7715).
Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 2 (
priority:p2,bug)Session:
session_014MXhk1yjWh37d634hLy3p7Account:
huangyiirene(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13082-rls-reference-passesWorktree:
objectui-issue-13082Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/app-shell/src/views/metadata-admin/celAuthoring.ts(rlsLowerabilityVerdictat about :284 of objectuimainb017621returns[]for a lowerable clause, so@objectstack/lint'svalidateRlsPredicateEnforceabilityreference passes never run in the editor), its caller's hint plumbing (CelPredicateField.tsx/PermissionAdvancedFacets.tsx) only if a pass needs metadata the editor already holds (objectName,fields), tests beside them, and one.changeset/13082-rls-reference-passes.md. Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuiover this surface reads no path-derived mandate)Clause-②: no
Responsibility: the risk is produced by objectui's own Studio CEL lint (
celAuthoring.tsasks the rule only for its shape pass); the platform path that covers it: the publish door, which runs the full rule and refuses with a 422, so nothing unenforceable goes live; who reaches it: every Studio author whose lowerable RLS predicate names something the rule refuses (e.g. an unknowncurrent_usermember).Thread-read: 6278250564
Serial constraints cleared: no open objectui PR touches
celAuthoring.ts,CelPredicateField.tsxorPermissionAdvancedFacets.tsx(open PR #13092, file list read at this claim). PR #13080 (objectui#13061), this card's precondition, is merged (2a75c83). objectui#13083 (alsoarea:access, queued) is a record-formvisibleWhencard on other files.Verification route (the filer's own card; the seat's call): the card asks for a Studio reproduction first. The reproduction runs through the real editor path (
lintCelPredicate/CelPredicateField) with the real@objectstack/lintrule at objectui's pin, the same function the publish door runs. A live Studio boot is required only if that cannot show the editor's silence.Why
Clause-②: no:celAuthoring.tsis internal to@object-ui/app-shell(the entry re-exports nothing from it), and the server's accept set does not move. A route that would widen a published face is outside this claim: the dev stops and reports it.Claimed at: 2026-10-19T22:12Z
objectstack-fleet commentedon Oct 19, 2026
os-dev-report
{ "issue": 13082, "status": "done", "branch": "claude/issue-13082-rls-reference-passes", "pr": "https://github.com/objectstack-ai/objectui/pull/13093", "session": "session_014MXhk1yjWh37d634hLy3p7 (subagent run; the harness-stamped Claude-Session is the parent PM session)", "premise_still_valid": true, "summary": "Reproduced first through the real editor path with the real @objectstack/lint rule at objectui's pin f4755a68a797: on base 6058bf8, lintCelPredicate('current_user.nope == owner_id') answered [] for USING and CHECK while the rule answers rls-predicate-unknown-user-variable at error, and PermissionAdvancedFacets reported 0 blocking errors (Save open). Fix in packages/app-shell/src/views/metadata-admin/celAuthoring.ts: rlsLowerabilityVerdict became rlsPredicateVerdict and asks validateRlsPredicateEnforceability about every clause that parses, on the same one-clause stack, carrying each finding's severity and message as written. The editor now carries every verdict that reads the clause alone: unknown-user-variable, the current_user type faults, and the shared-face null comparand (where the engine lets the clause parse). Named as left to publish, with reasons (in the docblock, the PR table and pinned by tests): unknown-field (the editor's list is read from the published object, so a field added in a pending object draft would be a false error holding Save; measured), the list-holding and cross-class arms (need declared field types; the editor holds names), and the engine judgeFilter pass (server only). PM hypothesis H2 is half falsified: feeding the object lets unknown-field judge but gives a false error on the draft-field case, so the object is not fed. H1, H3, H4 hold.", "tests": "Reproduction on base 6058bf8 (new pins, unchanged code): `pnpm exec vitest run --maxWorkers=2` over celAuthoring.rlsReferencePasses-13082.test.ts + PermissionAdvancedFacets.cel.test.tsx: Tests 13 failed | 15 passed (28); e.g. `expected [] to deeply equal [ { severity: 'error', ... } ]` and facets `expected last call [1], received [0]`. Final head 6cd39a5, under os-verify-lock: `pnpm exec vitest run --maxWorkers=2` over the 33 celAuthoring.* / CelPredicateField.* / PermissionAdvancedFacets.* / PermissionMatrixEditor.* test files in packages/app-shell/src/views/metadata-admin: Test Files 33 passed (33), Tests 310 passed (310), VERDICT command-exit 0. Ablation (scripts/ablation-replace.mjs, objectstack checkout): re-inserted the shape-only gate at the top of rlsPredicateVerdict; anchor x1 -> x0, replacement x0 -> x1, blob f9df94a897bc -> 017f941d05af; over the new file + PermissionAdvancedFacets.cel.test.tsx + celAuthoring.test.ts: Tests 13 failed | 57 passed (70) (red = 10 surfaced-verdict pins + 3 facets blocking pins; controls, left-to-publish, engine-first, shape and all objectui#13061 pins green); restored by the tool: blob f9df94a897bc == HEAD, git diff HEAD empty. A first ablation attempt was refused by the tool before running anything (replacement contained the anchor); nothing ran under it. No dist involved (tests import ./celAuthoring from source).", "gates": "Local, head 6cd39a5, exit captured before any pipe: closure build `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build` 0; `pnpm --filter @object-ui/app-shell type-check` 0 (tsconfig.test.json --listFilesOnly lists both edited test files); `pnpm --filter @object-ui/app-shell lint` 0 (0 errors; the one warning on a touched file is on untouched CelPredicateField code); `pnpm check:new-line-citations` 0 (0 new citation(s)); `pnpm check:control-bytes` 0; `pnpm check:changeset-claims` 0; `pnpm check:pending-changeset-literals` 0; `node scripts/check-changeset-presence.mjs` 0; `node scripts/check-changeset-no-major.mjs` 0; `pnpm check:test-path-roots` / `check:vi-mock-specifiers` / `check:vi-mock-inherit` / `check:vi-mock-override-shape` / `check:unreferenced-sources` 0 each; `node scripts/check-governed-queue-guard.mjs --test` over the 6 diff paths 0 (NOT GOVERNED). NOT MEASURED: `pnpm check:readme-exports`, reason: exit 1 on a prerequisite (type entries of app-shell and six other packages not built); the README hunk is a prose bullet with no fence; CI builds and runs it. i18n checks not run: no key moves. No --ran reconciliation: dispatch-gates.mjs refuses objectui, list hand-derived. CI check-runs on 6cd39a5 at report time (35): Changeset Fixed Group Check success, Changeset Bump Policy success, label success; Test (coverage) / dependabot / coverage shards skipped; in_progress: Test shards 1-16/16, Test (dist pins), Type Check, Lint, Repo Gates, Line Citation Gate, Build Docs, Build & E2E, Bundle Analysis, Governed Surface Queue Guard, Changeset Declaration, Changeset Claim Re-read, Changeset Overwrite Report, Live E2E (informational).", "mcp_calls": "0", "api_writes": "2 relay strokes (fleet-write, as objectstack-fleet[bot]): (1) pr_create via POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls (draft #13093) + POST /repos/objectstack-ai/objectui/issues/13093/assignees (huangyiirene), read-back identical 12531 bytes; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/13082/comments. Plus 2 git pushes of the branch (not REST). Reads only otherwise.", "diff": "6 files changed, 269 insertions(+), 48 deletions(-)", "files_changed": [ ".changeset/13082-rls-reference-passes.md", "packages/app-shell/README.md", "packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx", "packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.cel.test.tsx", "packages/app-shell/src/views/metadata-admin/celAuthoring.rlsReferencePasses-13082.test.ts", "packages/app-shell/src/views/metadata-admin/celAuthoring.ts" ], "deviations": [ "Outside the claim's file list, comments/docs only: one packages/app-shell/README.md bullet (AGENTS.md commandment 2) and two CelPredicateField.tsx comments (the claim lists that file for plumbing only; no plumbing moved). No export, prop or published face moves; Clause-2 stays no.", "PM suggested route not taken in its 'feed the object the editor knows' half: measured to give a false unknown-field error for a field added in a pending object draft (the editor's list is read from the published object), so the stack stays one clause, no object.", "No live Studio boot: the seat's route makes it conditional and the editor path showed the silence. The live publish 422 is NOT MEASURED; the door's verdict was read from the same rule function.", "Commit trailers follow objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named line; PR footer is the os-dev definition's session-URL form." ], "open_questions": [], "out_of_scope_findings": [ "carrier: none (承接者:无) · noted in PR Acceptance notes, not filed: the RLS editor's field list (loadObjectFields in PermissionMatrixEditor.tsx) reads the published object without the draft overlay, unlike useObjectFields (objectui#11895), so its autocomplete and near-miss advisory miss a field added in a pending object draft. Read-only inference, not reproduced in a running Studio. Surfacing rls-predicate-unknown-field in the editor would first need a decision on which universe that list mirrors. Dedupe words: RLS editor field list draft overlay; loadObjectFields previewDrafts; permission editor pending object draft field." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
ACCEPT → PR #13093 comment 6279068076 · no contract-review face hit (
Clause-②: no) ·domain:ui#1·session_014MXhk1yjWh37d634hLy3p7· 2026-10-19T22:49Z. The flip to ready and auto-merge wait for green check-runs on head6cd39a5.objectstack-fleet commentedon Oct 19, 2026
LANDED ·
domain:uiseat 1 ·session_014MXhk1yjWh37d634hLy3p7· 2026-10-19T23:12Z ·pm:dispatchedcleareda487ced, whichgit merge-base --is-ancestorplaces onorigin/main(exit 0)gh-readonly-queue/main/pr-13093-*branch remainsorigin/main,celAuthoring.tscarriesasync function rlsPredicateVerdict(1 hit) and norlsLowerabilityVerdict(0 hits). Positive control:validateRlsPredicateEnforceabilityis still the rule the editor asks (4 hits)6278527988(Clause-②: no), dev report6279041945, ACCEPT6279068076on PR #13093 (no contract-review face hit)completedat 2026-10-19T23:12Z through the PR'sFixes #13082, the only card closed since the merge;pm:dispatchedis removed in this actLeft at publish, as the PR states: unknown field, incompatible field types and the engine's filter check. The editor's field list is read from the published object, so a draft field would raise a false error there. Not filed: it is a read-only inference, recorded in the PR's Acceptance notes.