Repository navigation
fix(app-shell): Studio's Data pillar keeps platform-injected hidden system fields out of the grid, Form preview and designer (objectui#11780) - #11828
Merged
objectstack-fleet[bot] merged 2 commits intoOct 7, 2026
Conversation
…ystem fields out of the grid, Form preview and designer (objectui#11780) The records grid (`gridColumns`), the Form preview (`formFields`) and the form designer dropped framework fields by one fixed name list, which does not name the search companion `__search` or `owning_business_unit_id`, so every author saw both. The platform marks the columns it injects and hides with `system: true` + `hidden: true`; `isStudioHiddenSystemField` reads that pair off each field definition, beside the name list (which keeps the audit columns: `system` without `hidden`). - Author-hidden fields without `system` stay visible (the way to un-hide them). - `owner_id` (`system`, not hidden) stays visible. - The designer hides such fields from the canvas and writes them back with their definitions unchanged; one test serves the density count, the containers and the commit. - Memo keys are unchanged (`objDraft.fields`, plus `publishedFieldNames` for the grid). Claude-Session: https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z Co-authored-by: Claude <noreply@anthropic.com>
…onfig.test.json accepts them Claude-Session: https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
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
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-11780-studio-hidden-system-fields
branch
October 7, 2026 19:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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__searchandowning_business_unit_idare not on that list, so every author saw "Search Index" and "Owning Business Unit" in all three views, while the runtime list hides both.isStudioHiddenSystemField(def)instudio-design/studioHiddenSystemField.ts(not on the package entry):system === true && hidden === trueon the served field definition, per the seat's ruling. An author field withhidden: trueand nosystemstays visible; so doesowner_id(system, not hidden).gridColumnsandformFieldsdrop entries that match it, beside the unchanged name-list check. Memo keys are unchanged:objDraft.fields, pluspublishedFieldNamesfor 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 passesSTUDIO_SYSTEM_FIELD_NAMES.STUDIO_SYSTEM_FIELD_NAMESkeeps its job, measured below: the platform's audit columns aresystemwithouthidden, so the marks alone would put them back. Its doc block now says so.@object-ui/app-shell.Fence held: no
MetadataClient.savecall site, no version-token read, no change to the object-draft load effect, no edit to the metadata-admini18n.ts, no package-entry export, no type member, no locale key.ObjectFormDesigneris not re-exported from the app-shellindex.ts(grep: zero hits; the positive controlregisterMetadataPreviewhits).Measurements against the PM hypotheses
H1, measured live. objectstack
a543e244,examples/app-showcasebooted withobjectstack dev --seed-admin --freshon an isolated port, read through the same endpointsMetadataClient.layeredandgetDraftcall.showcase_account,GET /api/v1/meta/object/showcase_account/layers.effective.fieldsis 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 fieldname: hidden false, readonly false, no system. (code.fieldshas no__search; it is provisioned intoeffective.)doCreateObjectcreates one (the skeleton with onenamefield, saved with mode=draft into a Studio-created package), thenGET ...?state=draft.item.fieldsis organization_id, created_at, created_by, updated_at, updated_by, owner_id, owning_business_unit_id, name, __search.__searchandowning_business_unit_id: hidden true, system true, readonly true. Author fieldname: 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.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:
buildObjectSkeletonseeds onenametext 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(theobjectmetadata preview, mounted throughObjectPreviewin the metadata-admin editor) renders every entry throughgroupEntries(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 mountsObjectFormDesignerand 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.
showcase_accountRecords 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.git diff HEADempty): the headers include "Owning Business Unit" and "Search Index", and both designers show both labels.Pins
DataPillar.hiddenSystemFields-11780.test.tsxdrives the realDataPillar. The fixture copies the platform's own literals (provisionSearchCompanion,OWNING_BUSINESS_UNIT_FIELD_DEF,TENANT_SCOPE_FIELD_DEF, thecreated_atrow ofAUDIT_FIELD_DEFS). Each case runs twice: once on an object with no pending draft, and once with a served draft.__search,owning_business_unit_idandorganization_idare absent. The author fields are present.internal_note(authorhidden: true, nosystem) andowner_id(system, not hidden) stay.created_atstays out, by the name list.onDragEnd, with the realDndContextrendered) auto-savesfields. In those fieldsindustrynow leadsname, every hidden system field's definition is deep-equal to the served one, and the key set is unchanged.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 emptygit diff HEAD. Predicted direction first:gridColumnskey loosened toobjDraft: 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 0pnpm exec vitest runonStudioDesignSurface.gridColumns,StudioDesignSurface.formFields,ObjectFormDesigner, everyDataPillar.*test and the new pins: exit 0, 13 files, 56 tests passedpnpm 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 passedpnpm --filter @object-ui/app-shell type-check(echoestsc --noEmit && tsc -p tsconfig.test.json): exit 0pnpm check:control-bytesOK ·check:new-line-citationsVERDICT 0 new citation(s) ·check:changeset-claimsOK ·check:pending-changeset-literalsOK: all exit 0check:vi-mock-specifiers·check:vi-mock-inherit·check:vi-mock-override-shape(newvi.mockdoubles) ·check:test-path-roots·check:unreferenced-sources(new source file) ·check:metadata-write-doors: all exit 0. Alsonode scripts/check-changeset-presence.mjs,node scripts/check-changeset-no-major.mjsandnode scripts/check-governed-queue-guard.mjs --teston the changed paths (NOT GOVERNED): all exit 0.lintruns 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 ineslint.config.js, so this diff cannot move a verdict on an untouched file. The repo-widepnpm lintbelongs to CI.Acceptance notes
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.StudioDesignSurface.tsx: the import of the new helper, in the module's import block. In-flight draft PR fix(app-shell): Studio draft saves send the version they were built on, and a stale save opens a reload / overwrite dialog (objectui#11773) #11826 also adds an import there, in an earlier part of the block nearuseMetadataClient. The two hunks do not overlap, and neither do itsDataPillarhunks with this branch's.Session:
https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z(dispatching seat domain:ui#1).Generated by Claude Code