Repository navigation
Commit d53fd02
fix(app-shell): Studio's Data pillar keeps platform-injected hidden system fields out of the grid, Form preview and designer (objectui#11780) (#11828)
Fixes #11780
Clause-②: no
## What changed
Studio's Data pillar kept framework fields out of the records grid
(`gridColumns`), the Form preview (`formFields`) and the form designer
by one fixed name list, `STUDIO_SYSTEM_FIELD_NAMES`. The platform's
search companion `__search` and `owning_business_unit_id` are not on
that list, so every author saw "Search Index" and "Owning Business Unit"
in all three views, while the runtime list hides both.
- New module-private predicate `isStudioHiddenSystemField(def)` in
`studio-design/studioHiddenSystemField.ts` (not on the package entry):
`system === true && hidden === true` on the served field definition, per
the seat's ruling. An author field with `hidden: true` and no `system`
stays visible; so does `owner_id` (`system`, not hidden).
- `gridColumns` and `formFields` drop entries that match it, beside the
unchanged name-list check. Memo keys are unchanged: `objDraft.fields`,
plus `publishedFieldNames` for the grid.
- `ObjectFormDesigner`: one module-level test, `isKeptOffLayout(entry,
systemFieldNames)` (the name list OR the predicate), now serves all
three of its readers: the density count, the containers, and the
commit's write-back. A field kept off the canvas is therefore always
written back. No prop change; the mount still passes
`STUDIO_SYSTEM_FIELD_NAMES`.
- `STUDIO_SYSTEM_FIELD_NAMES` keeps its job, measured below: the
platform's audit columns are `system` without `hidden`, so the marks
alone would put them back. Its doc block now says so.
- Patch changeset for `@object-ui/app-shell`.
Fence held: no `MetadataClient.save` call site, no version-token read,
no change to the object-draft load effect, no edit to the metadata-admin
`i18n.ts`, no package-entry export, no type member, no locale key.
`ObjectFormDesigner` is not re-exported from the app-shell `index.ts`
(grep: zero hits; the positive control `registerMetadataPreview` hits).
## Measurements against the PM hypotheses
**H1, measured live.** objectstack `a543e244`, `examples/app-showcase`
booted with `objectstack dev --seed-admin --fresh` on an isolated port,
read through the same endpoints `MetadataClient.layered` and `getDraft`
call.
- No pending draft, `showcase_account`, `GET
/api/v1/meta/object/showcase_account/layers`. `effective.fields` is the
record shape. `__search`: hidden true, system true, readonly true.
`owning_business_unit_id`: hidden true, system true, readonly true.
`organization_id`: the same. `owner_id`: system true, readonly false, no
hidden. `created_at`: system true, readonly true, no hidden. Author
field `name`: hidden false, readonly false, no system. (`code.fields`
has no `__search`; it is provisioned into `effective`.)
- Served draft: an object created the way `doCreateObject` creates one
(the skeleton with one `name` field, saved with mode=draft into a
Studio-created package), then `GET ...?state=draft`. `item.fields` is
organization_id, created_at, created_by, updated_at, updated_by,
owner_id, owning_business_unit_id, name, __search. `__search` and
`owning_business_unit_id`: hidden true, system true, readonly true.
Author field `name`: label only. An object of a code-provided package
takes no draft (the save answers 403, read-only package), so the
served-draft case is a Studio-authored object.
- So the marks sit on the entries `readFields(objDraft.fields)` returns
in both cases. No second source was needed.
**H2, confirmed.** The three readers above are the leak. No separate
seed carries the injected fields: `buildObjectSkeleton` seeds one `name`
text field, the server adds the injected columns to the served draft,
and the designer's ungrouped bucket rendered them. That bucket is the
filer's "default layout seed".
**H3, confirmed and kept.** The designer's commit writes the kept-off
entries followed by the canvas entries. With the shared test, the
injected hidden fields ride the same path as the audit columns. Pinned
through the real pillar: a designer drop is auto-saved with both fields
present and their definitions deep-equal to the served ones.
**H4, not touched.** `ObjectFormCanvas` (the `object` metadata preview,
mounted through `ObjectPreview` in the metadata-admin editor) renders
every entry through `groupEntries(view, ...)` with no system filter of
any kind; it shows the audit columns too. It is a full field-inventory
editor, and the Data pillar does not mount it (the pillar mounts
`ObjectFormDesigner` and the grid). Hiding fields there would be a new
design decision, not this leak.
**H5, kept.** Both memo keys are unchanged. A new pin holds the grid
columns array at the same identity across an object-label edit made
through the real `onPatch`.
## Live check in the browser
The console dev server from this branch, proxied to that backend,
headless Chromium at 1440x900, signed in as the seeded admin.
- This branch: the `showcase_account` Records grid headers run Account
Name, Industry, ..., Owner, Loyalty Tier, LinkedIn URL, CSAT Score,
Actions. Neither "Search Index" nor "Owning Business Unit" appears. Both
designers (`showcase_account`, and the Studio-created object) show
neither label. The new object's designer shows Owner and Name.
- The same session with both source files set to the base commit
(restored afterwards; blob hashes equal HEAD, `git diff HEAD` empty):
the headers include "Owning Business Unit" and "Search Index", and both
designers show both labels.
## Pins
`DataPillar.hiddenSystemFields-11780.test.tsx` drives the real
`DataPillar`. The fixture copies the platform's own literals
(`provisionSearchCompanion`, `OWNING_BUSINESS_UNIT_FIELD_DEF`,
`TENANT_SCOPE_FIELD_DEF`, the `created_at` row of `AUDIT_FIELD_DEFS`).
Each case runs twice: once on an object with no pending draft, and once
with a served draft.
- Records grid, Form preview, designer: `__search`,
`owning_business_unit_id` and `organization_id` are absent. The author
fields are present.
- Controls: `internal_note` (author `hidden: true`, no `system`) and
`owner_id` (`system`, not hidden) stay. `created_at` stays out, by the
name list.
- Write-back: a designer drop (the captured `onDragEnd`, with the real
`DndContext` rendered) auto-saves `fields`. In those fields `industry`
now leads `name`, every hidden system field's definition is deep-equal
to the served one, and the key set is unchanged.
- Identity: an unrelated draft edit (the object label) leaves the grid
columns array at the same identity, and the save carries the new label.
- The predicate's truth table: both marks, booleans only.
Reverse checks. The fix was committed first. Each leg is restored with
`git checkout HEAD --`, then proven by a blob hash equal to HEAD and an
empty `git diff HEAD`. Predicted direction first:
1. Both source files at the base commit (marker counts 4 and 4 fell to 0
and 0): 6 failed, 5 passed. The failures are grid, Form preview and
designer, each twice; the first reads "expected [ 'name', 'industry',
... ] to not include '__search'". Write-back, identity and the predicate
stay green, as predicted.
2. The designer commit's write-back test changed back to the name list
alone: 2 failed (write-back, twice), "expected undefined to deeply equal
{ type: 'text', ... }". This leg proves the hidden fields would be
dropped.
3. The `gridColumns` key loosened to `objDraft`: 2 failed (identity,
twice).
The first attempt at leg 3 was a no-op: the script hit a syntax error
before the mutation landed (anchor count 1/0 unchanged, nothing
written). It was rerun with a corrected script, and the counts after the
mutation read 0/1.
## Gates (local HEAD 7343b3a)
- `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...'
build`: exit 0
- `pnpm exec vitest run` on `StudioDesignSurface.gridColumns`,
`StudioDesignSurface.formFields`, `ObjectFormDesigner`, every
`DataPillar.*` test and the new pins: exit 0, 13 files, 56 tests passed
- `pnpm exec vitest run packages/app-shell/src/views/studio-design/` (at
9feaf8b; 7343b3a changes only the new test file's mock typing): exit 0,
93 files, 548 tests passed
- `pnpm --filter @object-ui/app-shell type-check` (echoes `tsc --noEmit
&& tsc -p tsconfig.test.json`): exit 0
- `pnpm check:control-bytes` OK · `check:new-line-citations` VERDICT 0
new citation(s) · `check:changeset-claims` OK ·
`check:pending-changeset-literals` OK: all exit 0
- Added for this diff: `check:vi-mock-specifiers` ·
`check:vi-mock-inherit` · `check:vi-mock-override-shape` (new `vi.mock`
doubles) · `check:test-path-roots` · `check:unreferenced-sources` (new
source file) · `check:metadata-write-doors`: all exit 0. Also `node
scripts/check-changeset-presence.mjs`, `node
scripts/check-changeset-no-major.mjs` and `node
scripts/check-governed-queue-guard.mjs --test` on the changed paths (NOT
GOVERNED): all exit 0.
- Targeted eslint, as the package's `lint` runs it, on the four touched
source files: 0 errors. On the two modified files the warnings are the
same set as at the base commit (ObjectFormDesigner 1,
StudioDesignSurface 17). The new files have none. Type-aware linting is
not enabled in `eslint.config.js`, so this diff cannot move a verdict on
an untouched file. The repo-wide `pnpm lint` belongs to CI.
## Acceptance notes
- The designer's write-back puts the kept-off fields first in `fields`.
That was already true for the audit columns, and is now true for the
injected hidden ones. Their definitions are unchanged. Before this
change these fields sat in the ungrouped bucket and were rewritten at
that bucket's position, so a designer edit moved them before too.
- The object header's "N fields" count still counts every served field,
the system ones included. It did so before this change, and it is not on
this card's surface.
- One line outside the claim's listed regions of
`StudioDesignSurface.tsx`: the import of the new helper, in the module's
import block. In-flight draft PR #11826 also adds an import there, in an
earlier part of the block near `useMetadataClient`. The two hunks do not
overlap, and neither do its `DataPillar` hunks with this branch's.
Session: `https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z`
(dispatching seat domain:ui#1).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2dec305 commit d53fd02
5 files changed
Lines changed: 422 additions & 6 deletions
File tree
- .changeset
- packages/app-shell/src/views/studio-design
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 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 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
0 commit comments