Repository navigation
Description
domain:devx#1 · sunhaolin · session_017xRBcSwDXZrZg7nGjP6P3U
Filing gate: ① a product defect with a reproduction. It was found by QA run #27438 (wave 3 of the 18.3.0 sweep, anchor #27377) and re-derived by an independent verifier on a fresh boot (RUNNER rule 7). reach: measured at the Studio save door (PUT /api/v1/meta/permission/SET?mode=draft answers 200).
Business reason: authors, and AI authors in particular, treat a field that saves as a field that is fine. A row-level security predicate the engine will refuse keeps saving into the draft. The author only learns at Publish, and the published policy set never contains the rule they believe they wrote.
Reader who acts: the triage seat (domain, area, level), then the implementer for domain:ui (ui/packages/app-shell, the CEL authoring fields).
Dedupe (open AND closed):
- "RLS editor Valid CEL formula field USING predicate rls-predicate-unenforceable Studio": 16 hits. The nearest is Studio: an expression field that says "Valid CEL" should read the draft's server verdict at its own path (RLS predicate, flow edge condition) #26858 (closed by PR fix(app-shell): an expression field shows the draft's server verdict at its own path #26999, which is in the run subject as e6e4199). It made the field DISPLAY the server verdict, and that half holds. Its save-gate half is this card.
- "field inspector close Escape saves invalid formula draft held autosave bypass": 5 hits, none the same.
Batch-of: 16 · QA run #27438
Symptom
In Studio, an expression the engine refuses is never held by the save gate. The server's verdict is shown, but it is not counted as an error.
Reproduction (subject c4c515a, stock showcase, os dev)
- As admin, create a writable package with
POST /api/v1/packages. In it, publish:- an object with a number field
est_hoursand a formula fieldf_total(any formula overest_hours); - a permission set.
- an object with a number field
- Open
/_console/studio/PKG/access?surface=permission:SET, then the Row-level security tab. Add a policy on the object with USINGf_total > 5(record.f_total > 5behaves the same). - Observed:
- The field reads "Valid CEL", and
perm-autosave-heldnever appears. - About 3 s later,
PUT /api/v1/meta/permission/SET?mode=draft&package=PKG&surface=studioanswers 200.
- The field reads "Valid CEL", and
- The re-read about 0.1 s later (
GET …?state=draft) carries_diagnosticsvalid:falsewithrls-predicate-unenforceableatrowLevelSecurity.0.using. The field now shows the server's message witharia-invalid=true, and it still does after navigating away and back, and after a reload. - With that message on screen, edit the predicate to
f_total > 7. It autosaves again (200). POST …/publishanswers 422rls-predicate-unenforceable.
The same class on the Validations tab (measured by the sibling runner on studio-authoring.validation-rules-authoring): a rule predicate comparing a nullable field without a null check reads "Valid CEL" and autosaves (PUT 200), while the draft read already answers _diagnostics.valid:false. The author learns it only from "Not published… Details".
Expected (studio-authoring.expression-editors acceptance[4]): a predicate the engine refuses raises a blocking error, and the save is held (celErrorCount above 0).
Actual: the client lint passes the predicate, so the save is not held. The server verdict reaches the field's display but not the hold.
Mechanism (read from source at c4c515a, to be confirmed by the implementer)
celAuthoring.tslints the RLS predicate as a one-clause stack that names no object, so the virtual-field branch of the engine's rule cannot fire on the client.- fix(app-shell): an expression field shows the draft's server verdict at its own path #26999 feeds the draft read's verdict into
CelPredicateFieldby path, for display only. It never feeds the count that holds the autosave (celErrorCount). - So any rule the client cannot replicate (formula-field USING, the nullable-compare rule) saves until Publish refuses it.
The fix likely lets a server error at the field's own path hold the save, the same as a client error does. ⛔ It should not add a second client copy of the publish rule (#26858's constraint).
QA-source: #27438 · studio-authoring.expression-editors · acceptance[4]
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | studio-authoring.expression-editors | P③
Triage: p2 ·
domain:ui·area:studio· 2026-10-29T12:10Z⛔ Not a claim.
bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Claim: PM loop round 1
Session:
session_01Utp6CaJoinvGQSbHeDaWBeAccount:
os-billBranch:
claude/project-thread-yv2fej(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27482Domain:
domain:uiSeat:
domain:ui#3File surface:
ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx(RLS save-hold region),ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx,ui/packages/app-shell/src/views/metadata-admin/celAuthoring.tsonly if needed, the Validations tab hold site, tests beside, root.changeset/(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieronee9a8d6e: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: ui code produces the defect | no platform path covers it | every Studio / console author reaches it today
Thread-read: 6496277111
Premise: holds
Serial constraints cleared: no open PR edits PermissionMatrixEditor.tsx, CelPredicateField.tsx or celAuthoring.ts · seat-3 sibling #27511 fold holds StudioDesignSurface.tsx's selection/autosave region; a Validations-tab hold site there is another region · #27513 waits for this card (its verdict half rides this fix)
Dispatched 2026-10-29T13:13Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaN9smHqkJcUWF4adR
os-dev-report
{ "issue": 27482, "status": "done", "branch": "claude/project-thread-yv2fej", "pr": "https://github.com/objectstack-ai/objectstack/pull/27612", "head": "48c334adb568203891d2b5aaff40dbdb67511f34", "session": "session_01Utp6CaN9smHqkJcUWF4adR (card thread; seat session_01Utp6CaJoinvGQSbHeDaWBe)", "premise_still_valid": true, "summary": "RLS arm done: a served _diagnostics error at a CelPredicateField's own verdictPath now counts in PermissionMatrixEditor's celErrorCount (reported through the existing onLintChange, so PermissionAdvancedFacets is untouched), which holds the package door's autosave and disables the environment door's Save. The hold applies only while the field shows the text the verdict judged (new DraftVerdictBodyContext + serverHoldAt in draftVerdict.ts, seat-approved surface widening); editing the text away releases, so the save goes out and its re-read brings the next verdict, avoiding the deadlock a path-only hold would cause (no validate-only door exists). No client copy of the publish rule. Validations-tab arm NOT done (deviation): no server verdict reaches the Data pillar. PR body says Part of #27482.", "tests": "48c334ad (post-merge): pnpm --dir ui exec vitest run over 92 files (every metadata-admin test of PermissionMatrixEditor/CelPredicateField/draftVerdict/ConditionalFormatting/ResourceEditPage verdict + every ui test importing CelPredicateField/draftVerdict/ConditionBuilder, incl. the new PermissionMatrixEditor.serverVerdictHold-27482.test.tsx) -> Test Files 92 passed, Tests 811 passed, lock VERDICT command-exit 0; pnpm --filter @object-ui/app-shell type-check -> VERDICT command-exit 0. Same set on bee1b7d1 before the merge: 92/92, 811/811. Ablation 1 (CelPredicateField report ignores held server errors, anchor 'server.length === 0' made always true, via scripts/ablation-replace.mjs, src resolved directly so no build): cases a,b,d red, c green as expected (release path); restored blob == HEAD, git diff HEAD empty. Ablation 2 (draftVerdict serverHoldAt ignores the text): unit 'holds on the judged text, and not on any other' red + integration (c) red (the deadlock); restored blob == HEAD. eslint on the 5 changed files: 0 errors, 20 warnings all on pre-existing lines.", "gates": "dispatch-gates --commands (tree 8bd055e5, 6 paths): 34 families, each recorded '<command> :: exit <code>' before any pipe, all exit 0 (pnpm --dir ui exec vitest run scripts/ first returned 99 behind my own lock hold, re-run alone: exit 0, 169 files / 4901 tests passed). dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED. node scripts/check-sdui-manifest.mjs exit 0 (in the list). ui pnpm check:new-line-citations: 0 new citations, exit 0. CI families: in_progress at report time, read from PR #27612 check-runs by the seat.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "n/a — no skills/** touched", "files_changed": [ ".changeset/27482-server-verdict-holds-cel-autosave.md", "ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.serverVerdictHold-27482.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/draftVerdict.ts", "ui/packages/app-shell/src/views/metadata-admin/draftVerdict.test.ts" ], "deviations": [ "Validations-tab arm not implemented: ObjectValidationsPanel has a hold counter (per-rule celErrors -> onBlockingIssuesChange -> DataPillar Save gate) but DataPillar in StudioDesignSurface.tsx reads the object draft via readDraftForSave(client, 'object', ...) and keeps only extractDraftBody, dropping _diagnostics; it provides no DraftVerdictContext, and ConditionBuilder passes no verdictPath to its CelPredicateField. Wiring: keep the object draft read's _diagnostics + body in DataPillar (load and post-save), provide DraftVerdictContext + DraftVerdictBodyContext, give ConditionBuilder a per-rule verdictPath. Server path spelling for a validation rule condition NOT MEASURED. Region held by sibling card #27511 fold; seat agreed to a follow-up (same chain as #27513). Hence 'Part of #27482', not 'Fixes'.", "File surface widened to ui/packages/app-shell/src/views/metadata-admin/draftVerdict.ts, seat-approved in thread before the edit.", "The full metadata-admin + studio-design directory run produced no output for 40 min and was killed (my own PID); replaced by the 92-file set above. Directory-wide run left to CI Test UI.", "Harness after-PR assign/review step skipped per the dispatch order (maintainer rule: no os-bill assignee or review request at open).", "PR body Human Minimum item 3 reads 'pnpm lint passes on the changed files': measured by eslint on those 5 files only; repo-wide lint is CI's." ], "mcp_calls": "0 — no GitHub MCP tool used", "api_writes": "2 — git push (not REST); relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> PR #27612); this report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/27482/comments)", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — the permission-set held status line reuses perm.cel.saveBlocked ('Fix the CEL syntax errors before saving.') for the server-verdict hold too; the field shows the server's own message, so not misleading enough to file; wording lives in the studio i18n namespace a sibling card is editing", "carrier: none · noted, not filed — field-level when conditions in the permission matrix pass no verdictPath, so they neither show nor hold a server verdict (the server judges fields[].when with the RLS rule); dotted object.field keys make the path spelling ambiguous, unmeasured" ] }objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
ACCEPT → PR #27612 comment 6500236027 · 2026-10-29T15:01Z
12 remaining items
objectstack-fleet commentedon Nov 3, 2026
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
2026-11-03T00:55Z
New evidence from QA run #29672 on
mainat3482f3d8d2. Runner readings, re-driven on an isolated origin, not re-derived by the PM seat. ⛔ Not a claim; no state or label is changed here.studio-authoring.expression-editors[2], [4], [6]. An RLSUSINGon a formula field reads "Valid CEL", and its first PUT answers 200; publish then answers 422.studio-authoring.validation-rules-authoring[1].record.qty > 1000on a nullable number: PUT 200 under a redcel-server-error,aria-invalidtrue, no held line, reproduced 3 of 3. Editing the message PUTs again. Syntax and unknown-field errors do hold, so this fails only on conditions the publish gate calls invalid.The maintainer ruled in chat, 2026-11-03, to file the run's results; these two items are parked here rather than on a new card.
objectstack-fleet commentedon Nov 3, 2026
domain:devx#1 · os-warren · session_01JQwxbXGDmSYVyFomEEAdU3
Re-measured on
mainat589049b0(18.3.0 wave-5 run, QA run #29893,studio-authoring.validation-rules-authoringacceptance[1], 2 of 2 fresh loads): the Validations door still autosaves a condition the server refuses. Nullable numberqty, "Reject the save when…" → Expressionrecord.qty > 1000→PUT /api/v1/meta/object/OBJ?mode=draft200, then the red server verdict ("applies>torecord.qty, which 'OBJ' declares as nullable…"),aria-invalid=true, no held line, status "Saved"; message and condition edits each PUT 200 again;publish-draftsrefuses it (expression-invalid). One new reading: adding a second rule raised the pillar line "Not saved yet: an expression on the rule … has an error to fix" and held the object, so the hold engages only once the author leaves the offending rule. The parse-error shape (… &&) is held at the input, as before.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: orphaned epic reservation released ·
pm:epic→pm:queue· 2026-11-08T11:13Z⛔ Not a claim.
pm:epic, but its epic, [Epic] Studio designs, Setup administers (ADR-0146): one editor per metadata item, in-place customization on read-only packages, the paired<base>.customizepackage, the metadata catalog moves into Studio #28130, closed at 2026-10-30T18:41Z. No epic PM reserves it any more, and lane seats are barred from it by the label, so nobody can take it. The latest state comments (QA re-measures, 11-03) carry no hold or freeze.pm:epicis removed andpm:queueadded, in one write (seat-lifecycle: 离开子树…同一笔标签写摘pm:epic加pm:queue). p2,domain:ui,area:studioare unchanged. The QA evidence in the comments above is the resume point.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jVEjiYrK7onirxUGyo
Claim: PM loop round 1 · 2026-11-08T12:17Z
Session:
session_01QsR2jSGK8zPYdrSzXgFLDf(card thread, dev) · seatsession_01QsR2jVEjiYrK7onirxUGyoAccount:
zhuangjianguoBranch:
claude/project-thread-0oxzdkWorktree:
objectstack-issue-27482Domain:
domain:uiSeat:
domain:ui#3File surface:
ui/packages/app-shell/src/views/metadata-admin/**(CelPredicateField, ConditionBuilder, the autosave hold), its tests, locale packs if copy changes, root.changeset/; ⛔ nopackages/lint,packages/specor server changeContainer & model: M,
mode:thread,model: default tier(dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
ui/packages/app-shell/src/views/metadata-adminautosave hold in objectstack counts client lint only while the offending rule is open | the platform path is the draft read's_diagnosticsat the field's own key path (validations.N.condition, #27675;serverHoldAt, #27612 / #28027) | Studio authors, AI authors above all; a refused predicate keeps saving until Publish refuses itThread-read: 6720776303
Premise: open, step 1 owed: both layers landed (#27612, #28027, both merged before the re-measures), yet QA #29672 and #29893 on 11-03 still read the symptom (6592489919, 6600831225); the dev re-measures on
origin/main58f66b937before any codeSerial constraints cleared: other
domain:uicards in build on this seat are #31472, #31492, #31494 and #27482, on disjoint source files; any shared locale-pack lines are serialised by the merge queueScope: the card's Expected (acceptance[4] of
studio-authoring.expression-editors) as narrowed by the step-1 report; ⛔ no client copy of the publish rule (#26858). PR saysFixes #27482. Brief:/mnt/project-files/issue-27482/brief.md.objectstack-fleet commentedon Nov 8, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jVEjiYrK7onirxUGyo
Claim amendment · 2026-11-08T12:43Z · claim 6721388863
Step-1 report read (card thread
session_01QsR2jSGK8zPYdrSzXgFLDf, measured live onorigin/main58f66b937). Answers:ObjectValidationsPanelkeys each rule's CEL count by name (reportCel(sel.name!, count), L1410), a panel-minted rule's name follows its message (patchMessage, L1047), andConditionBuilderre-reports only when its count changes, so a rename strands the count under the dead name. A rule with an authored name holds today. RLS: only the first PUT goes out before the verdict, by design.ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx(carry the kept count from the old name to the new one on a rename, about 8 lines) and…/metadata-admin/DataPillar.validationVerdictHold-27644.test.tsx(new describe).perm.cel.saveBlockedsays "syntax errors" for errors that are not syntax errors. Its value changes in the studio namespaceen.tsandzh.ts(the only two packs that carry it), plus the 2 metadata-admin pins that quote it. It is an existing key with a new value and no new key, soClause-②: nostands.node scripts/check-i18n-en-drift.mjsfromui/must be green (en and zh change together).Metadata-protocol: nonestands.objectstack-fleet commentedon Nov 8, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jSGK8zPYdrSzXgFLDf
os-dev-report
{ "issue": 27482, "status": "done", "branch": "claude/project-thread-0oxzdk", "pr": "https://github.com/objectstack-ai/objectstack/pull/31549", "head": "c1768bdcec1d40ac3e2a2e1da33beb46e655d4b2", "session": "session_01QsR2jSGK8zPYdrSzXgFLDf (card thread; seat session_01QsR2jVEjiYrK7onirxUGyo)", "premise_still_valid": true, "summary": "Step 1 measured live on main 58f66b93: the served verdict reached the hold, but ObjectValidationsPanel keeps each rule's CEL count by rule NAME and a panel-minted rule renames itself as its message is edited; ConditionBuilder re-reports only when its count changes, so the count was stranded under the dead name and pruned, and a refused guard autosaved on every edit (authored-name rules and the RLS arm held). Fix (surface amended by the seat): patchRule carries the count to the new name on any rename, and reportCel resolves a report still in flight under the old name through a renamedTo map (that race reddened the new case 3 of 4 runs before it was handled). Copy perm.cel.saveBlocked now reads 'Fix the expression errors before saving.' (zh updated). Acceptance reading per the seat ruling is in the PR body: first save goes out; once the verdict shows the next save is held, a rename included; a guard edit goes out.", "tests": "c1768bdc: pnpm --dir ui exec vitest run over 39 nearby files (ObjectValidationsPanel / Validations tab / perm.cel.saveBlocked / held-line pins, studio-namespace, draftVerdict, ConditionBuilder.serverHold-27644, PermissionMatrixEditor.serverVerdictHold-27482) -> Test Files 39 passed, Tests 275 passed, lock VERDICT command-exit 0. turbo type-check app-shell + i18n 68/68 exit 0 at c1768bdc. Harness DataPillar.validationVerdictHold-27644 9/9 in 4 consecutive runs (67e8fea8). Ablation 1 (rename carry deleted via ablation-replace, anchor 1->0, restored blob == HEAD 00af991baf66, git diff HEAD empty): new cases (a) and (b) red, control and #27644 cases green. Ablation 2 (renamedTo walk made a no-op): (a) red 1 of 2 runs (timing race). Live before/after (fresh showcase + Console Vite + Playwright, issue-27482/live/): before, minted rule 4 PUTs no held line; after, message rename and label edits held (1 PUT), guard edit PUTs, RLS held line shows the new copy. ui check-i18n-en-drift exit 0; ui check:new-line-citations 0 new.", "gates": "dispatch-gates --commands at c1768bdc: 36 families, each recorded 'CMD :: exit N' before any pipe, all exit 0 (check-sdui-manifest included; type-check-debt and ui vitest scripts/ 170 passed under the lock). dispatch-gates --ran: 36 derived, 36 run, 0 NOT-MEASURED. PR body gates on the final body: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword all exit 0. CI families: in_progress at report time, read from PR 31549 check-runs by the seat.", "dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm", "line_budget": "n/a - no skills/** touched; diff +120 -5 over 7 files (src +25 -1, tests +79 -2, copy +2 -2, changeset +13)", "files_changed": [ ".changeset/27482-rule-rename-keeps-verdict-hold.md", "ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx", "ui/packages/app-shell/src/views/studio-design/DataPillar.validationVerdictHold-27644.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.fieldWhen-25866.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.rlsAddPolicyHold-13113.test.tsx", "ui/packages/i18n/src/namespaces/studio/en.ts", "ui/packages/i18n/src/namespaces/studio/zh.ts" ], "deviations": [ "The fix is about 25 source lines, not the ~8 the step-1 report budgeted: the renamedTo resolution for in-flight reports was added after the first version's new test was red 3 of 4 runs.", "check:test-source-alias required module-top preloads in the edited test files: import of @objectstack/lint in the 27644 harness and of @objectstack/formula, @objectstack/lint, @objectstack/spec/identity in the two PermissionMatrixEditor pins (both already in the amended surface); commit d2fd8a4c.", "The 4-run stability reading of the harness was taken at 67e8fea8, before the preload commit and the merge of main; the file then ran green in the 39-file sweep at c1768bdc." ], "mcp_calls": "3 - GitHub MCP reads only: issue_read get (27482), issue_read get_comments x2 (27482)", "api_writes": "2 - relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> PR 31549, read back identical 8359 bytes); this report via post-stamped (POST /repos/objectstack-ai/objectstack/issues/27482/comments). git push x4 (not REST).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none - noted, not filed: ObjectActionsPanel keys its CEL verdicts by action name too, but grep finds no derived-name rename there, so the stranding does not reproduce on that panel today" ] }objectstack-fleet commentedon Nov 8, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jVEjiYrK7onirxUGyo
ACCEPT → PR #31549 comment 6722783047 · 2026-11-08T14:35Z · head
c1768bdc(a rule's blocking CEL count follows its rename, so a server-refused guard holds the next save;perm.cel.saveBlockedno longer says "syntax"; 125 lines, not governed,Fixes #27482). Clause-② no. Landing through the merge queue.objectstack-fleet commentedon Nov 8, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jVEjiYrK7onirxUGyo
Landed · 2026-11-08T15:22Z
ba875d2c9329e7d43b59e3a2d987da24fada3a43onmaincompletedby the PR'sFixes; labelsbug,priority:p2,domain:ui,area:studio(pm:dispatchedremoved)Delivered: a permission rule's blocking CEL count follows the rule when it is renamed, so a guard the server refused still holds the next save instead of being dropped with the old name; the
perm.cel.saveBlockedmessage no longer calls every refusal a "syntax" error. Remaining: none filed.