Repository navigation
Commit ea684a0
fix(app-shell): a server error at an RLS clause's path holds the permission-set autosave (#27612)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wg4i9JiKjEjwtuVzd4gKy9hB)_
## 维护者速读
- 改了什么:Studio 权限集编辑器里,RLS 的 USING/CHECK 子句若被服务端草稿裁决判为发布时会拒绝(如 USING
读公式字段),现在会像 CEL 语法错误一样挡住自动保存,并在字段上显示服务端原话。
- 为什么改:之前服务端裁决只用于显示、不计入保存门,作者看着报错却一直 200 保存,到 Publish 才 422。
- 风险与回滚:只改 app-shell
三个文件;裁决只在「字段文本等于裁决所评判的文本」时挡保存,改掉文本即放行(下一次保存的重读带来新裁决),避免死锁。回滚即 revert 本
PR。
- 先看:`CelPredicateField.tsx` 的 `report` 与 `heldKey` 效果;`draftVerdict.ts`
的 `serverHoldAt`;`PermissionMatrixEditor.tsx` 里与 `servedVerdict` 同步设置的
`servedVerdictBody`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.serverVerdictHold-27482.test.tsx`,预期
4 条全绿。
- 需要你做的:无,席位落地。
Part of #27482
Clause-②: no
Metadata-protocol: none
This closes the RLS arm of the card. The Validations-tab arm is not done
here and is listed under Acceptance notes, so the merge must not close
the card.
## What changes
- `draftVerdict.ts`: a second context, `DraftVerdictBodyContext`,
carries the body the served verdict judged. `valueAtPath` reads a dotted
`_diagnostics` path in that body, and `serverHoldAt` / `useServerHoldAt`
answer the served errors at a field's path only while the field shows
the text that body holds there. No rule is restated: the server's errors
are taken whole.
- `CelPredicateField.tsx`: a field with a `verdictPath` reports those
held server errors through `onLintChange` as blocking errors, beside its
lint findings. It re-reports when the hold starts, changes or lapses,
keyed on the messages rather than on the array identity. Display is
unchanged.
- `PermissionMatrixEditor.tsx`: `servedVerdictBody` is set beside
`servedVerdict` at each of its three reads (the load, the package door's
post-save draft read, the environment door's post-save layered read) and
provided to the RLS facets. The existing count, `celErrorCount`, now
includes those errors, so the package door's autosave holds and the
environment door's Save is disabled.
## Why
The draft read's `_diagnostics` reached the RLS clause's display
(#26858) but never `celErrorCount`, so a predicate the publish refuses
(a USING over a formula field, `rls-predicate-unenforceable`) kept
autosaving with the server's message on screen. Triage asked for exactly
this: a server error at the field's own path counts in `celErrorCount`,
with no second client copy of the publish rule.
The verdict judges the stored draft and nothing else, and no door judges
a text without storing it. Holding every edit while an error stands at
the path would deadlock: the corrected clause could never be saved, so
the next draft read could never clear it. So the hold applies while the
clause still shows the judged text. Editing the clause away lets that
one save go out, and its re-read brings the next verdict.
## Tests
- `PermissionMatrixEditor.serverVerdictHold-27482.test.tsx` (new, 4
cases, fake door decides the refusal): (a) a stored refused draft holds
another edit, no PUT, message stays; (b) the card flow: the refused
clause saves once, its re-read holds the next edit; (c) editing the
clause away releases, the save goes out and its clean re-read clears the
verdict; (d) typing back to the judged text before the autosave fires is
held again, no PUT.
- `draftVerdict.test.ts`: four new cases for `valueAtPath` and
`serverHoldAt` (judged text holds, other text does not, no body / no
path / no error at that exact path holds nothing, an absent value reads
as empty text).
## Acceptance notes
- **File surface widened, seat-approved:**
`ui/packages/app-shell/src/views/metadata-admin/draftVerdict.ts`, the
home of the served-verdict helpers. `PermissionAdvancedFacets.tsx` is
untouched: the held errors ride the existing `onLintChange` report.
- **Validations tab, not done (deviation):** its hold counter exists
(`ObjectValidationsPanel`'s per-rule map, reported through
`onBlockingIssuesChange` to the Data pillar's Save gate), but no server
verdict reaches the Data pillar at all. `DataPillar` in
`StudioDesignSurface.tsx` reads the object draft through
`readDraftForSave(client, 'object', …)` and keeps only
`extractDraftBody`, dropping `_diagnostics`; it provides no
`DraftVerdictContext`, and `ConditionBuilder` passes no `verdictPath` to
its `CelPredicateField`. Wiring it is: keep the object draft read's
`_diagnostics` and body in `DataPillar` (load and post-save), provide
both contexts, and give `ConditionBuilder` a `verdictPath` per rule. The
hold then applies with no further change to the field. The server's path
spelling for a validation rule's condition is not measured here. That
region belongs to a sibling card in flight, so it is left to a
follow-up.
- **The first save of a newly refused text still goes out.** Nothing on
the client knows the refusal before the server stores and judges the
text, and a client copy of the rule is ruled out. So in the card's step
5 the edit to another refused text saves once, and its re-read holds
what follows.
- **Status line wording:** the held line reads the existing
`perm.cel.saveBlocked` ("Fix the CEL syntax errors before saving."),
which also covers this server-verdict hold; the field itself shows the
server's message. Rewording it is left alone (the studio namespace is in
a sibling card's diff).
- **Field-level `when` conditions** in the permission matrix pass no
`verdictPath`, so they show and hold no server verdict, as before.
## Verification
Readings name the commit they ran on.
<details><summary>Tests</summary>
- New and changed tests on 02780608: 2 files, 11/11 passed.
- Neighbouring suites on bee1b7d (every metadata-admin test of
PermissionMatrixEditor, CelPredicateField, draftVerdict,
ConditionalFormatting, the ResourceEditPage verdict tests, and every ui
test file that imports `CelPredicateField`, `draftVerdict` or
`ConditionBuilder`): 92 files, 811/811 passed.
- `pnpm --filter @object-ui/app-shell type-check`: exit 0.
- Post-merge re-run on 48c334a (after `origin/main` merged, install and
the app-shell dependency closure rebuilt): the same 92 files, 811/811
passed; `type-check` exit 0.
</details>
<details><summary>Ablations (each committed first, mutated through
scripts/ablation-replace.mjs, restored with blob == HEAD and an empty
git diff HEAD)</summary>
1. `CelPredicateField.tsx`, the report ignores the held server errors
(the anchor `server.length === 0` made always true): cases (a), (b), (d)
red, (c) green. Expected: (c) is the release path.
2. `draftVerdict.ts`, the hold ignores the text (the judged-text
comparison replaced by a constant true): the unit case "holds on the
judged text, and not on any other" red and integration case (c) red, the
deadlock this design avoids. Everything else green.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --commands` on this diff: 34
families, all run, all exit 0 (`--ran` reconciliation: 34 derived, 34
run, 0 NOT-MEASURED). `node scripts/check-sdui-manifest.mjs` exit 0.
`pnpm check:new-line-citations` (ui): 0 new citations. Every family CI
runs is read from this PR's check runs.
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(No spec change.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes on the changed files
(eslint, see the report).
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: not touched.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Utp6CaN9smHqkJcUWF4adR)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent e29a1b1 commit ea684a0
6 files changed
Lines changed: 371 additions & 33 deletions
File tree
- .changeset
- ui/packages/app-shell/src/views/metadata-admin
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
| 57 | + | |
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
128 | | - | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
129 | 136 | | |
130 | 137 | | |
131 | | - | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
132 | 142 | | |
133 | 143 | | |
134 | 144 | | |
| |||
206 | 216 | | |
207 | 217 | | |
208 | 218 | | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
209 | 224 | | |
210 | 225 | | |
211 | 226 | | |
| 227 | + | |
212 | 228 | | |
213 | 229 | | |
214 | 230 | | |
| 231 | + | |
215 | 232 | | |
216 | 233 | | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
217 | 255 | | |
218 | 256 | | |
219 | 257 | | |
| |||
223 | 261 | | |
224 | 262 | | |
225 | 263 | | |
226 | | - | |
| 264 | + | |
227 | 265 | | |
228 | 266 | | |
229 | 267 | | |
| |||
246 | 284 | | |
247 | 285 | | |
248 | 286 | | |
249 | | - | |
| 287 | + | |
250 | 288 | | |
251 | 289 | | |
252 | 290 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
0 commit comments