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 }}
Repository navigation
Studio RLS editor: "Add policy" autosaves the blank row it inserts, so a 422 lands as a raw spec-validation banner (rowLevelSecurity.0.name [invalid_format]) before the author types anything, and the row is lost on reload #13113
Filing gate: ① user-visible UX defect (Studio write feedback is wrong). Reader: the objectui dev seat that takes this card from the pm-dispatch queue; fix lands in packages/app-shell/src/views/metadata-admin (PermissionAdvancedFacets / PermissionMatrixEditor). Dedupe: objectui issues, open+closed, semantic queries "RLS Add policy autosave empty policy spec validation error rowLevelSecurity name" (4 hits: #13082, #13061, #4302, #2413) and "permission set editor new RLS row saved before name entered 422 error banner" (4 hits: #13082, #13061, #4302, #4533) — none covers an incomplete NEW row being autosaved; this wave's #13061 / #13082 are about CEL predicates that publish refuses, not about the blank row.
reach: Studio (package door) → Access → a writable permission set → Row-level security tab → click "Add policy". Measured on stock showcase (--seed-admin), framework 54159fd742e5, console pin objectui@12dc7b47c340, dist stamp equal to the pin. Within ~1.5 s, with nothing typed, the page shows a red banner: "permission/visit_readers failed spec validation: 2 issues — rowLevelSecurity.0.name [invalid_format]; rowLevelSecurity.0 [custom]". The network shows PUT /api/v1/meta/permission/visit_readers?mode=draft&package=... answered 422. Reloading the page shows "No row-level policies" — the row the author was about to fill in is gone.
Expected: a freshly inserted policy row is local, incomplete state. Nothing is sent until it is complete enough to pass the protocol (a name in the accepted format at least), and while it is held the editor says, next to the row, what is missing ("Give the policy a name to save it"). If the server does refuse a save, the message names the field in the author's words (Policy name), not a schema path.
Actual: the autosave sends the blank row immediately, and the refusal is rendered as the raw protocol string with spec paths and zod codes (rowLevelSecurity.0.name [invalid_format]; rowLevelSecurity.0 [custom]). The author has done nothing wrong yet and sees an error they cannot map to the form; the unsaved row is then lost on reload.
Repro:
Boot stock showcase with --seed-admin, sign in as admin@objectos.ai.
Home → "Build an app" → "New package (writable base)" → any name → Create package.
Access → "New permission set" → any name → create it.
Row-level security tab → "Add policy". Do not type anything. Wait 2 s.
Observe the banner above; reload and observe the policy row is gone.
Source (objectui main df943a2, re-read before filing):
packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx — the "Add policy" button's onClick appends { name: '', object: '*', operation: 'all', using: '', enabled: true } straight into the draft via setPolicies.
packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx — useDraftAutoSave's blocked is !packageId || !writable || saving || celErrorCount > 0 || destructive !== null; an incomplete row (empty name) does not hold the autosave, only a CEL lint error does.
The banner prints the server's refusal string as-is (setError with the raw message).
Generic blocks / contract: no new widget. The fix is a hold condition on the existing shared autosave (an RLS row with no valid name is "incomplete", same as a CEL error) plus a per-row inline hint; the protocol's accepted name format is the gate (PermissionSet rowLevelSecurity[].name in packages/spec).
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on objectui origin/main4b67746498.
Filing gate. All three answers are present: ① measured in the browser, the objectui dev seat, and two searches of 4 hits each, closed included.
Premise. The "Add policy" flow lives in packages/app-shell/src/views/metadata-admin (PermissionMatrixEditor / its facets). The 422, the raw rowLevelSecurity.0.name [invalid_format] banner and the lost row are the filer's browser measurement at the console pin.
Why p2. Adding a row-level policy in Studio opens with an error the author did not cause, worded in schema paths, and the row is gone on reload. That is the first step of every RLS policy an author writes.
Shape.
A new row stays local until it passes the protocol's own minimum (a name in the accepted format). While held, it says beside the row what is missing.
A server refusal names the field in the author's words.
⛔ The editor does not restate the protocol's rule. It reads the refusal the door gives (objectui#7715's rule).
Claim: PM loop round 16 (priority:p2)
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13113-rls-add-policy-hold
Worktree: objectui-issue-13113
Domain: domain:ui
Seat: domain:ui#2
File surface:
packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx (useDraftAutoSave's blocked) and PermissionAdvancedFacets.tsx (the "Add policy" row). An RLS row the protocol would refuse (no name in the accepted format) holds the autosave, the same way a CEL lint error does, and the row says beside itself what is missing.
Where the save path renders a server refusal, it names the field in the author's words, read from the refusal the door gives and not restating the protocol's rule (objectui#7715).
New copy goes in the designer i18n table (en + zh).
Tests beside them.
One .changeset/13113-rls-add-policy-hold.md (@object-ui/app-shellpatch).
⛔ No new package export. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; no path-derived mandate over this surface)
Clause-②: no (internal metadata-admin editor; no export, prop or key moves)
Responsibility: the editor's autosave sends a just-inserted blank RLS row | the shared autosave already holds on a CEL error, and the protocol's name rule is in the spec | every author adding a row-level policy in Studio (the first step of every RLS policy)
Thread-read: 6282978730
Serial constraints cleared: objectui#12725's PR #13106 (df943a2, PermissionMatrixEditor save surface) landed. No open objectui PR touches these files (read at 04:27Z).
Claimed at: 2026-10-20T04:27Z
{
"issue": 13113,
"status": "done",
"branch": "claude/issue-13113-rls-add-policy-hold",
"pr": "https://github.com/objectstack-ai/objectui/pull/13167",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "PermissionMatrixEditPage now holds the shared autosave while any RLS row in the draft has an empty or blank name. The test is emptiness only; the spec regex is not restated. The environment Save button is disabled for the same reason. The row shows an inline hint, perm.rls.nameNeeded in en and zh, and the status line repeats it in a neutral tone. A refused save whose MetadataError.issues name rowLevelSecurity.N.name reads 'Not saved. Policy name, on row N+1: PROBLEM', with the server's own message; any other issue path keeps the transport text. The held row stays in the in-memory draft. A reload discards it, because nothing unsaved is persisted (ruling 3 allows this). Branch head 9a6cdafe39 (fix f318298686 + refactor) was checked against all three rulings and needed no further commit.",
"tests": "All at HEAD 9a6cdafe39, under os-verify-lock. Closure build --filter '@object-ui/app-shell^...' build: VERDICT command-exit 0. New file PermissionMatrixEditor.rlsAddPolicyHold-13113.test.tsx: 5/5 passed, covering pins (a), (b), (c) and both (d) controls. Family vitest --maxWorkers=1 over metadata-admin/PermissionMatrixEditor* + PermissionAdvancedFacets*: 28 files / 196 tests passed. i18n family (CelPredicateField.i18n*, studio-locale.i18n, metadata-form-i18n): 3 files / 22 tests passed. app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json): exit 0, and --listFilesOnly includes the new test. Ablation 1 (saveHeld = celErrorCount > 0): (a) and (b) red, 2 failed / 3 passed. Ablation 2 (setError without rlsNameRefusal): (c) red, 1 failed / 4 passed. Both mutations went through objectstack scripts/ablation-replace.mjs (anchor 1 to 0, blob 864d2df7b5b3 changed to 3188f0cad1aa and to 49781175306c). Both restores were proven: blob 864d2df7b5b3 equals HEAD:path and git diff HEAD has 0 lines. A trap restored on EXIT. Tests resolve src through a relative import, so no dist rebuild was needed. Narrowed lint: eslint --no-inline-config --format json over the 4 changed ts/tsx files gave 4 files, 0 errors, 23 warnings, all on pre-existing lines. No type-aware linting is configured, so untouched files' verdicts cannot change. Full pnpm lint and the full packages/app-shell directory run are declared to CI.",
"mcp_calls": "0",
"api_writes": "2 relay strokes: (1) fleet-write pr_create on objectstack-ai/objectui, which is POST /repos/objectstack-ai/objectui/pulls (draft) plus POST /repos/objectstack-ai/objectui/issues/13167/assignees, read back as identical with assignee baozhoutao; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/13113/comments via post-stamped. git push: none needed, because the branch was already at 9a6cdafe39 on origin.",
"gates": {
"head": "9a6cdafe39",
"closure-build": 0,
"type-check": 0,
"vitest-targeted": 0,
"vitest-new-file": 0,
"vitest-i18n-family": 0,
"ablation-1-red": 1,
"ablation-2-red": 1,
"restores-blob-proven": 0,
"lint-narrowed": 0,
"check:phantom-deps": 0,
"check:self-import": 0,
"check:unreferenced-sources": 0,
"check:doc-example-readers": 0,
"check:handler-key-reads": 0,
"check:side-effects-array": 0,
"check:element-data-source-declaration": 0,
"check:spec-symbols": 0,
"check:action-forward-parity": 0,
"check:designer-field-key-parity": 0,
"check:icon-record-names": 0,
"check:i18n-keys": 0,
"check:i18n-drift": 0,
"check:i18n-designer-parity": 0,
"check:control-bytes": 0,
"check-hand-rolled-comment-mask": 0,
"check-changeset-fixed": 0,
"check:spec-floors": "1 - NOT MEASURED, reason: prerequisite no-artifact (workspace build required), as the order anticipated",
"app-shell full dir": "declared to CI",
"pnpm lint full": "declared to CI"
},
"line_budget": "+333 / -5 across 5 files (test 215, PermissionMatrixEditor.tsx +83/-5, PermissionAdvancedFacets.tsx +19, i18n.ts +4, changeset 12)",
"files_changed": [
".changeset/13113-rls-add-policy-hold.md",
"packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx",
"packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx",
"packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.rlsAddPolicyHold-13113.test.tsx",
"packages/app-shell/src/views/metadata-admin/i18n.ts"
],
"deviations": [
"This run resumed from the pushed sha claude/issue-13113-rls-add-policy-hold@9a6cdafe39 after a container restart. It reused the healthy, clean worktree at that sha and added no new commits. Every verification above was re-run in this session; none comes from the lost session's record.",
"No labels were written: objectui path labels belong to labeler.yml, and the order named none.",
"The order says to run each touched package's directory under the lock, and also says no whole-package-directory runs. This run followed the second instruction: it ran the named families and declared packages/app-shell to CI.",
"Commit subjects carry '(#13113)' in prose. There are no card trailers, and the only trailers are Co-authored-by Claude and Claude-Session."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none, so noted only in the PR Acceptance notes. studio-design/metadataError.ts issueRefusal/IssueLocator is the general author-words refusal path. The permission editor's string error strip cannot use it without a MetadataSelection target, so this card's mapping is local. Not filed."
]
}
Clause-②: no. This is an internal metadata-admin editor; no export, prop or key moves. No contract review is owed, and the seat read the diff.
Seat review against the rulings:
(1) The autosave holds (saveHeld = celErrorCount > 0 || rlsUnnamedCount > 0) on emptiness only: a name that is not a non-blank string. The spec's name regex is not restated. The env Save button is disabled with the same reason, and the row and the status line say "give the policy a name".
(2) A refusal is mapped from the door's own MetadataError.issues. The one regex matches the issue pathrowLevelSecurity.N.name, not the name's format. The message is the server's, through translateValidationMessage, and other issues keep the transport text.
(3) The held row stays in the in-memory draft. A reload discards it, as ruling 3 allows.
Resumed after a container restart from the pushed 9a6cdafe39. Every verification was re-run in the resumed session:
5 new pins (hold, typing saves, a mapped 422, CEL-hold control, complete-row control);
families of 28 files / 196 tests and the i18n family;
two ablations, each red as intended, with restores proven by blob;
the full battery.
Changeset: @object-ui/app-shellpatch.
CI: all 36 check-runs completed on the head, 33 passed and 3 skipped. Mergeable state: clean.
Path fork: no governed path, 338 changed lines. Seat landing.
Findings: Acceptance notes. studio-design/metadataError.ts's general author-words refusal path needs a MetadataSelection target that this editor's string strip lacks, so the mapping is local here.
Next: ready + auto-merge; landing is verified by content on main.
Verified by content: each of the 5 files the PR changes has the same blob at 427e59c9e0 as at the accepted head 9a6cdafe39. The merge message carries no model identifier.
Landed:
Studio's permission editor holds the autosave while an RLS row has no name, and says so beside the row;
a server refusal of a policy name reads "Policy name, on row N: …" in the author's words, not the raw schema path;
Activity
objectstack-fleet commentedon Oct 20, 2026
Triage: p2 ·
bug· lanedomain:ui·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-20T03:53ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on objectui
origin/main4b67746498.Filing gate. All three answers are present: ① measured in the browser, the objectui dev seat, and two searches of 4 hits each, closed included.
Premise. The "Add policy" flow lives in
packages/app-shell/src/views/metadata-admin(PermissionMatrixEditor/ its facets). The 422, the rawrowLevelSecurity.0.name [invalid_format]banner and the lost row are the filer's browser measurement at the console pin.Why p2. Adding a row-level policy in Studio opens with an error the author did not cause, worded in schema paths, and the row is gone on reload. That is the first step of every RLS policy an author writes.
Shape.
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Claim: PM loop round 16 (
priority:p2)Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13113-rls-add-policy-holdWorktree:
objectui-issue-13113Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx(useDraftAutoSave'sblocked) andPermissionAdvancedFacets.tsx(the "Add policy" row). An RLS row the protocol would refuse (no name in the accepted format) holds the autosave, the same way a CEL lint error does, and the row says beside itself what is missing..changeset/13113-rls-add-policy-hold.md(@object-ui/app-shellpatch).⛔ No new package export. Stop on breach; explain in the report.
Container & model:
S,mode:subagent,model: opus(default tier; no path-derived mandate over this surface)Clause-②: no (internal metadata-admin editor; no export, prop or key moves)
Responsibility: the editor's autosave sends a just-inserted blank RLS row | the shared autosave already holds on a CEL error, and the protocol's name rule is in the spec | every author adding a row-level policy in Studio (the first step of every RLS policy)
Thread-read: 6282978730
Serial constraints cleared: objectui#12725's PR #13106 (
df943a2,PermissionMatrixEditorsave surface) landed. No open objectui PR touches these files (read at 04:27Z).Claimed at: 2026-10-20T04:27Z
Generated by Claude Code
fix(app-shell): hold an unnamed RLS policy instead of autosaving it, …
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 13113, "status": "done", "branch": "claude/issue-13113-rls-add-policy-hold", "pr": "https://github.com/objectstack-ai/objectui/pull/13167", "session": "session_01XVp19E1MYUTFM3dnkwz8gB", "premise_still_valid": true, "summary": "PermissionMatrixEditPage now holds the shared autosave while any RLS row in the draft has an empty or blank name. The test is emptiness only; the spec regex is not restated. The environment Save button is disabled for the same reason. The row shows an inline hint, perm.rls.nameNeeded in en and zh, and the status line repeats it in a neutral tone. A refused save whose MetadataError.issues name rowLevelSecurity.N.name reads 'Not saved. Policy name, on row N+1: PROBLEM', with the server's own message; any other issue path keeps the transport text. The held row stays in the in-memory draft. A reload discards it, because nothing unsaved is persisted (ruling 3 allows this). Branch head 9a6cdafe39 (fix f318298686 + refactor) was checked against all three rulings and needed no further commit.", "tests": "All at HEAD 9a6cdafe39, under os-verify-lock. Closure build --filter '@object-ui/app-shell^...' build: VERDICT command-exit 0. New file PermissionMatrixEditor.rlsAddPolicyHold-13113.test.tsx: 5/5 passed, covering pins (a), (b), (c) and both (d) controls. Family vitest --maxWorkers=1 over metadata-admin/PermissionMatrixEditor* + PermissionAdvancedFacets*: 28 files / 196 tests passed. i18n family (CelPredicateField.i18n*, studio-locale.i18n, metadata-form-i18n): 3 files / 22 tests passed. app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json): exit 0, and --listFilesOnly includes the new test. Ablation 1 (saveHeld = celErrorCount > 0): (a) and (b) red, 2 failed / 3 passed. Ablation 2 (setError without rlsNameRefusal): (c) red, 1 failed / 4 passed. Both mutations went through objectstack scripts/ablation-replace.mjs (anchor 1 to 0, blob 864d2df7b5b3 changed to 3188f0cad1aa and to 49781175306c). Both restores were proven: blob 864d2df7b5b3 equals HEAD:path and git diff HEAD has 0 lines. A trap restored on EXIT. Tests resolve src through a relative import, so no dist rebuild was needed. Narrowed lint: eslint --no-inline-config --format json over the 4 changed ts/tsx files gave 4 files, 0 errors, 23 warnings, all on pre-existing lines. No type-aware linting is configured, so untouched files' verdicts cannot change. Full pnpm lint and the full packages/app-shell directory run are declared to CI.", "mcp_calls": "0", "api_writes": "2 relay strokes: (1) fleet-write pr_create on objectstack-ai/objectui, which is POST /repos/objectstack-ai/objectui/pulls (draft) plus POST /repos/objectstack-ai/objectui/issues/13167/assignees, read back as identical with assignee baozhoutao; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/13113/comments via post-stamped. git push: none needed, because the branch was already at 9a6cdafe39 on origin.", "gates": { "head": "9a6cdafe39", "closure-build": 0, "type-check": 0, "vitest-targeted": 0, "vitest-new-file": 0, "vitest-i18n-family": 0, "ablation-1-red": 1, "ablation-2-red": 1, "restores-blob-proven": 0, "lint-narrowed": 0, "check:phantom-deps": 0, "check:self-import": 0, "check:unreferenced-sources": 0, "check:doc-example-readers": 0, "check:handler-key-reads": 0, "check:side-effects-array": 0, "check:element-data-source-declaration": 0, "check:spec-symbols": 0, "check:action-forward-parity": 0, "check:designer-field-key-parity": 0, "check:icon-record-names": 0, "check:i18n-keys": 0, "check:i18n-drift": 0, "check:i18n-designer-parity": 0, "check:control-bytes": 0, "check-hand-rolled-comment-mask": 0, "check-changeset-fixed": 0, "check:spec-floors": "1 - NOT MEASURED, reason: prerequisite no-artifact (workspace build required), as the order anticipated", "app-shell full dir": "declared to CI", "pnpm lint full": "declared to CI" }, "line_budget": "+333 / -5 across 5 files (test 215, PermissionMatrixEditor.tsx +83/-5, PermissionAdvancedFacets.tsx +19, i18n.ts +4, changeset 12)", "files_changed": [ ".changeset/13113-rls-add-policy-hold.md", "packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx", "packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx", "packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.rlsAddPolicyHold-13113.test.tsx", "packages/app-shell/src/views/metadata-admin/i18n.ts" ], "deviations": [ "This run resumed from the pushed sha claude/issue-13113-rls-add-policy-hold@9a6cdafe39 after a container restart. It reused the healthy, clean worktree at that sha and added no new commits. Every verification above was re-run in this session; none comes from the lost session's record.", "No labels were written: objectui path labels belong to labeler.yml, and the order named none.", "The order says to run each touched package's directory under the lock, and also says no whole-package-directory runs. This run followed the second instruction: it ran the named families and declared packages/app-shell to CI.", "Commit subjects carry '(#13113)' in prose. There are no card trailers, and the only trailers are Co-authored-by Claude and Claude-Session." ], "open_questions": [], "out_of_scope_findings": [ "carrier: none, so noted only in the PR Acceptance notes. studio-design/metadataError.ts issueRefusal/IssueLocator is the general author-words refusal path. The permission editor's string error strip cannot use it without a MetadataSelection target, so this card's mapping is local. Not filed." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
ACCEPT — PR #13167 @
9a6cdafe39405c586cdb7ea1343c79c8ca68bd87·domain:uiseat 2 (session_01XVp19E1MYUTFM3dnkwz8gB)saveHeld = celErrorCount > 0 || rlsUnnamedCount > 0) on emptiness only: a name that is not a non-blank string. The spec's name regex is not restated. The env Save button is disabled with the same reason, and the row and the status line say "give the policy a name".MetadataError.issues. The one regex matches the issue pathrowLevelSecurity.N.name, not the name's format. The message is the server's, throughtranslateValidationMessage, and other issues keep the transport text.9a6cdafe39. Every verification was re-run in the resumed session:@object-ui/app-shellpatch.studio-design/metadataError.ts's general author-words refusal path needs aMetadataSelectiontarget that this editor's string strip lacks, so the mapping is local here.Next: ready + auto-merge; landing is verified by content on
main.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gBmain427e59c9e0.427e59c9e0as at the accepted head9a6cdafe39. The merge message carries no model identifier.pm:dispatchedis removed.Generated by Claude Code