Skip to content

fix(app-shell): the RLS editor asks the lint rule about every clause that parses (objectui#13082) - #13093

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-13082-rls-reference-passes
Oct 19, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-13082-rls-reference-passes

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #13082

Clause-②: no

What changed

Studio's RLS policy editor now asks @objectstack/lint's validateRlsPredicateEnforceability about every USING / CHECK clause that parses, not only about one the runtime cannot lower. Before, rlsLowerabilityVerdict in celAuthoring.ts returned nothing as soon as isSupportedRlsExpression accepted the clause, so the rule's reference passes never ran in the editor. A lowerable predicate the publish door refuses, the card's current_user.nope == owner_id, linted clean and autosaved.

  • Verdict and words. rlsPredicateVerdict (renamed from rlsLowerabilityVerdict) hands the rule the same one-clause stack as before and carries back each finding's severity and message as written. No sentence is written in objectui, and nothing is synthesized: what the rule does not say, the editor does not say. For the card's predicate the editor now shows the rule's rls-predicate-unknown-user-variable message, which names current_user.nope as a value nothing pre-resolves and ends "so the policy is dropped and grants no access" (CHECK: "admits no write"). It is an error, so Save and the package-door autosave hold.
  • Shape verdict of objectui#13061 unchanged. A clause that cannot lower still gets the shape pass's error alone (pinned again in the new file).
  • Removed. The isSupportedRlsExpression member of the feature-detected FormulaModule shape: the pre-check was its only reader.
  • Docs. celAuthoring.ts docblocks, two CelPredicateField.tsx comments and one packages/app-shell/README.md bullet now describe the rule's verdicts, not lowerability alone.
  • Changeset. @object-ui/app-shell patch.

Landing point as claimed: packages/app-shell/src/views/metadata-admin/celAuthoring.ts. No hint plumbing moved: no pass the editor can judge needs more than the clause (see the table below). Outside the claim's file list, as comments and docs only: the two CelPredicateField.tsx comments and the README bullet, which would otherwise describe only the shape pass (AGENTS.md commandment 2). No export, prop or published key moves; celAuthoring.ts stays internal to @object-ui/app-shell.

First act: the reproduction, through the real editor path

Per the seat's verification route, the reproduction runs through the real editor path with the real @objectstack/lint rule at objectui's pin (f4755a68a797): lintCelPredicate, and PermissionAdvancedFacets mounting CelPredicateField and reporting blocking errors to PermissionMatrixEditor's Save gate. On base 6058bf8 the new pins fail exactly where the card says:

  • lintCelPredicate('current_user.nope == owner_id', { clause: 'using' }) answered [] (CHECK the same), while the rule on the same one-clause stack answers one rls-predicate-unknown-user-variable finding at error.
  • PermissionAdvancedFacets reported 0 blocking errors up for the predicate in USING, in CHECK and in both (expected 1, 1, 2), so Save stayed open.

Run on base: Tests 13 failed | 15 passed (28) over the two pin files. A live Studio boot was not needed: the editor path showed the silence. NOT MEASURED: the live publish 422 on a running server, reason: the rule the editor now asks is the function the runtime publish gate runs (runtime-authoring-gate.ts passes the shared rules, this one included), so the door's verdict was read from the function.

Every pass of the rule, and where each lives now

Read from packages/lint/src/validate-rls-predicate-enforceability.ts at the pin, and probed through the installed rule.

Pass (rule id, severity) Reads Editor holds it? Now
Shape: not lowerable / unparseable / over budget (rls-predicate-unenforceable, -unparseable, -over-budget, error) the clause yes surfaced since objectui#13061, unchanged
A current_user member nothing pre-resolves, in a scalar position (rls-predicate-unknown-user-variable, error) the clause, plus the spec's kernel key set yes surfaced
A current_user value of the wrong type for its position: a set under ==, one value or the whole context on the right of in (rls-predicate-unenforceable, error) the clause yes surfaced
A comparand the shared filter faces refuse: a null list member or ordering bound (rls-predicate-unenforceable, error) the clause yes surfaced where the engine lets the clause parse (status in [null]); status in ['a', null] and amount > null are already the engine's blocking type error, and the rule is asked only once a clause parses
An unknown field (rls-predicate-unknown-field, error) the object's field map as the publish universe holds it: live objects plus the drafts a package publish carries no: the editor holds field names read from the published object left to publish: fed that list, the rule refuses a field the author added in a pending object draft, which the package publish accepts (measured below)
A field compared with a list- or object-holding field (rls-predicate-unenforceable, error) declared field types no: names only left to publish
A field compared with a field of another comparison class (rls-predicate-unenforceable, error) declared field types no: names only left to publish
The engine's admission of the read scope (rls-predicate-unenforceable, error) the host engine's judgeFilter no: server only left to publish

Mechanism hypotheses, measured

  • H1 holds. The rule runs the shape pass, and for a clause isSupportedRlsExpression accepts, the reference pass; every id and what it reads is in the table. All severities are error at the pin.
  • H2: half holds, half falsified. Adding the object as the editor knows it does let the unknown-field pass judge: with the field names only, nope_field == current_user.id gets rls-predicate-unknown-field. The type arms stay silent on names only (status != amount, status != tags: no finding), and an empty field map gives no finding. The partial case is falsified. The editor's list comes from the host's loadObjectFields, which reads client.get('object', name) without the draft overlay (useMetadataClient sets previewDrafts only inside ?preview=draft). A field added in a pending object draft is therefore missing: region == 'EU' against that list answers rls-predicate-unknown-field, and against the universe the package publish judges (draft folded in) answers nothing. That is a false error holding Save on a predicate the door accepts, so the object is not fed to the stack and the pass stays at publish. The PM's suggested route (feed the object when known) is replaced by this, as its own condition required.
  • H3 holds. The unknown-user-variable pass reads the clause and the spec's kernel keys only: on a one-clause stack it refuses current_user.nope == owner_id in both clauses, and it keeps its own silence on an app-staged membership key (owner_id in current_user.team_ids: no finding, pinned).
  • H4 holds. owner_id == current_user.id is clean on both clauses and reports 0 blocking errors up; the objectui#13061 shape tests pass unchanged (celAuthoring.test.ts, PermissionAdvancedFacets.cel.test.tsx).

Tests (head 6cd39a5)

New celAuthoring.rlsReferencePasses-13082.test.ts. Every expected finding is read from the published rule at call time; no message is written in the test:

  • Acceptance 1: current_user.nope == owner_id in USING and in CHECK lints to exactly the rule's rls-predicate-unknown-user-variable error; owner_id == current_user.id stays clean in both.
  • Acceptance 2, surfaced: owner_id == current_user.org_user_ids, owner_id in current_user.id, status in current_user and status in [null], both clauses, each the rule's rls-predicate-unenforceable error. Also pinned: the engine refuses the mixed null list and the null ordering bound first, with exactly one blocking error; and the app-staged key stays silent.
  • Acceptance 2, left to publish: a field missing from the editor's list holds no Save, though the rule refuses it against that list and accepts it with the draft field present; absent field metadata (undefined, []) gives no error; the two type arms are refused by the rule over declared types and give no editor error.

PermissionAdvancedFacets.cel.test.tsx: the card's predicate in USING, in CHECK and in both reports 1, 1 and 2 blocking errors up; the control on both clauses reports 0 with both editors showing the valid affordance.

Run from the worktree root under the verify lock: pnpm exec vitest run --maxWorkers=2 over the 33 celAuthoring.*, CelPredicateField.*, PermissionAdvancedFacets.* and PermissionMatrixEditor.* test files under packages/app-shell/src/views/metadata-admin/. Result: Test Files 33 passed (33), Tests 310 passed (310), lock verdict command-exit 0. The full app-shell suite is CI's.

Ablation (one-off, not kept)

Mutation via scripts/ablation-replace.mjs (objectstack checkout): put the objectui#13061 gate back at the top of rlsPredicateVerdict (return nothing when the engine's isSupportedRlsExpression accepts the clause), that is, shape-pass-only again. Anchor x1 -> x0, replacement x0 -> x1, blob f9df94a897bc -> 017f941d05af. Over the new file, PermissionAdvancedFacets.cel.test.tsx and celAuthoring.test.ts: Tests 13 failed | 57 passed (70). Red: the ten surfaced-verdict pins and the three facets blocking pins. Green as expected: both controls, the app-staged key, the shape pin, the two engine-first pins, the four left-to-publish pins and every objectui#13061 test. Restored by the tool: blob f9df94a897bc equals HEAD, git diff HEAD empty. A first attempt was refused by the tool before it ran anything (its replacement contained its anchor, so the anchor count could not drop); nothing ran under it. No dist/ is involved: the tests import ./celAuthoring from source.

Gates (local, head 6cd39a5)

Command Exit
pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build (closure) 0
pnpm --filter @object-ui/app-shell type-check (both projects; --listFilesOnly shows tsconfig.test.json reads both test files) 0
pnpm --filter @object-ui/app-shell lint 0 (0 errors; the one warning on a touched file, CelPredicateField.tsx, is on untouched code)
pnpm check:new-line-citations 0 (0 new citation(s))
pnpm check:control-bytes 0
pnpm check:changeset-claims / check:pending-changeset-literals 0 / 0
node scripts/check-changeset-presence.mjs / check-changeset-no-major.mjs 0 / 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 diff 0 (NOT GOVERNED)
pnpm check:readme-exports NOT MEASURED: exit 1 on a prerequisite (type entry ./dist/index.d.ts is not on disk for app-shell itself and six other unbuilt packages). The README hunk is a prose bullet with no fenced block; CI builds and runs it.

No i18n key moves, so the i18n checks were not run. dispatch-gates.mjs refuses objectui, so this list was derived by hand from the diff.

Acceptance notes

  • Why an unknown field is not the editor's error. The editor's field list (loadObjectFields in PermissionMatrixEditor.tsx) reads the published object, while authoring surfaces elsewhere read the draft-overlaid one (useObjectFields, objectui#11895). Even with the overlay, the single-item publish door and the package batch see different universes. Making the editor judge unknown fields at error therefore needs a decision on which universe the RLS editor's field list should mirror. That is not this card's. Today an unknown field gets at most the engine's non-blocking near-miss warning, and publish refuses it.
  • Observation, not filed (read-only inference). The same published-only read means the RLS editor's field autocomplete and near-miss advisory do not see a field added in a pending object draft. Not reproduced in a running Studio; recorded here only.
  • Package scope. The publish door judges against the package's closure (packageScope). The editor judges the clause alone, so no scope question arises for the verdicts it now carries.

Generated by Claude Code

…only an unlowerable one (objectui#13082)

Studio's RLS editor asked `@objectstack/lint`'s
`validateRlsPredicateEnforceability` only for a clause
`isSupportedRlsExpression` refuses. A lowerable predicate the rule
refuses on what it reads, such as `current_user.nope == owner_id`
(`rls-predicate-unknown-user-variable`), linted clean and autosaved.

`rlsPredicateVerdict` now asks the rule for every USING / CHECK clause
that parses, on the same one-clause stack, and carries each finding's
severity and message as written. The verdicts that read the clause
alone reach the editor; the ones that read the object's field map, its
field types or the host engine stay at publish, for the reasons the
docblock gives.

Claude-Session: https://claude.ai/code/session_014MXhk1yjWh37d634hLy3p7
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests package: app-shell labels Oct 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/11806-login-server-unreachable.md

  • names packages/app-shell/README.md → packages/app-shell/README.md — edited by this change

    packages/app-shell/README.md documents the two new states in its sign-up table. Its useSignUpOffer recipe for hosts now asks decideSignUpOffer only once the read has answered, and answers unreachable for a failed read.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with cd4623d06 (merge-base with origin/main): 5 file(s) changed outside .changeset/, read against 824 pending declaration(s) that publish a body (848 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 77 chunks) 3207.9 KB 3744.1 KB
Main entry chunk (gzip) 81.5 KB 350 KB
Entry file index--Psl7oTL.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (buildIdentity.js) 0.80KB 0.49KB
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.17KB 7.81KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 615.08KB 149.86KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 252.05KB 70.40KB
fields (index.js) 292.36KB 74.70KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.33KB 11.96KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 55.04KB 16.10KB
plugin-charts (index.js) 85.14KB 23.42KB
plugin-chatbot (index.js) 238.47KB 56.30KB
plugin-dashboard (index.js) 147.53KB 39.95KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 265.63KB 70.60KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 184.11KB 47.60KB
plugin-gantt (index.js) 178.46KB 45.13KB
plugin-grid (index.js) 272.91KB 75.73KB
plugin-kanban (index.js) 64.49KB 19.83KB
plugin-list (index.js) 148.80KB 38.90KB
plugin-map (index.js) 27.17KB 9.00KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.31KB 11.88KB
plugin-tree (index.js) 15.27KB 5.40KB
plugin-view (index.js) 94.68KB 24.36KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 126.45KB 41.40KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · objectui#13082 · PR #13093 · domain:ui#1 · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-19T22:48Z

Head 6cd39a549783dcd8e5d0f9ddb128c398f7dc02e2. Reviewed against the claim 6278527988 and the dev report on objectui#13082, read on GitHub rather than from the report. No contract-review record is owed. The claim and the PR body read Clause-②: no. celAuthoring.ts is internal to @object-ui/app-shell, and the server's accept set does not move (the editor only adopts more of the publish door's own verdicts). There is no schema and no governed path.

  1. Shape: draft PR against main. The body's first line is Fixes #13082, the only closing keyword. Assignee huangyiirene. 6 files, +269 / −48. Not Tier H.
  2. Premise, re-measured: at 6058bf8, rlsLowerabilityVerdict returned [] whenever isSupportedRlsExpression passed, so a lowerable clause never reached the rule's reference passes. The dev reproduced it first on the base through the real editor path and the real @objectstack/lint rule at objectui's pin: current_user.nope == owner_id gave [] for USING and CHECK, and the facets reported 0 blocking errors. The diff asks validateRlsPredicateEnforceability about every clause that parses, on the same one-clause stack, keeping each finding's severity and message as written. No verdict is synthesized.
  3. Gates: the dev's local runs at 6cd39a5: 33 metadata-admin test files, 310 tests pass. The new pins went 13 red on the base (the reproduction). The ablation (re-inserting the shape-only gate) turns exactly the 10 surfaced-verdict pins and 3 blocking pins red, while the controls, the left-to-publish pins and every objectui#13061 pin stay green; the restore was proved by blob hash. app-shell type-check and lint, new-line citations, control bytes, the changeset, vi-mock, test-path and unreferenced-source checks, and the queue guard (NOT GOVERNED) exit 0. The flip to ready waits for every check-run on this head to be green or an expected skip.
  4. Accepted deviations:
    • The seat's suggested route "feed the object the editor knows" was measured and declined: the editor's field list is read from the published object, so a field added in a pending object draft would raise a false rls-predicate-unknown-field error holding Save. The stack stays one clause, and unknown-field is named as left to publish. This follows the brief's own rule that absent metadata is never a refusal.
    • No live Studio boot: the seat's route made it conditional, and the editor path showed the silence.
    • Comment and README edits on CelPredicateField.tsx and packages/app-shell/README.md keep the prose true.
    • Changeset sentences checked against the diff: a lowerable predicate the rule refuses "is now the rule's error, in the rule's words, and it holds Save and autosave"; the type and null-comparand verdicts that read the clause alone follow; "A valid predicate such as owner_id == current_user.id stays clean"; and unknown field, incompatible field types and the engine's filter check "stay at publish", each with its reason. All match the code and the pins.
  5. Out of scope: the RLS editor's field list (loadObjectFields) reads the published object without the draft overlay useObjectFields applies (objectui#11895), so its autocomplete and near-miss advisory miss a draft field. Dropped: it is a read-only inference, not reproduced in a running Studio, and it stays in the PR's Acceptance notes.
  6. Landing: not Tier H, and no contract-review face is hit, so needs:contract-review is not hung. Once the check-runs on this head are green, the seat flips to ready and enables auto-merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: app-shell tests

Projects

None yet

2 participants