Skip to content

docs(plugin-charts, plugin-form, plugin-list, app-shell): census of the object-schema snake lookup reads — all seven legs keep, with the evidence recorded at each site - #7649

Draft
os-sam wants to merge 1 commit into
mainfrom
claude/issue-7642-object-schema-snake-lookup-census
Draft

docs(plugin-charts, plugin-form, plugin-list, app-shell): census of the object-schema snake lookup reads — all seven legs keep, with the evidence recorded at each site#7649
os-sam wants to merge 1 commit into
mainfrom
claude/issue-7642-object-schema-snake-lookup-census

Conversation

@os-sam

@os-sam os-sam commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Part of #7642

Census only. Zero sites retired, zero runtime change (102 insertions, 0 deletions:
comments plus one empty-frontmatter changeset). Per the dispatching ruling, the census
is the deliverable and the retirements were conditional on it.

Verdict: all seven legs KEEP

The card's argument is that FieldSchema is strict, the four snake spellings are
absent, therefore no producer can emit them. Measured against the spec installed in
this repo, with all controls lit, that is true — of the authoring path. Three
further measurements moved every site to KEEP.

1. The serve path runs no parse

ObjectStackAdapter.getObjectSchema returns the server document verbatim plus exactly
two rewrites (normalizeSchemaReferenceKeys, applyFieldWidgetOverrides). Count of
ObjectSchema.parse/safeParse on that path: 0, against a lit control (the same
file does use DroppedFieldsEventSchema and isFilterAST). So FieldSchema's
strictness gates authoring, not serving: a stored pre-strict document still
delivers these keys to every one of these consumers. The legs are not unreachable.

2. Five of the six sites have no camelCase leg at all

Measured per file, control lit. Only ObjectFieldInspector reads a camel spelling off
the field def. For the other five, retiring the snake read does not re-point the read
to the declared spelling — it deletes the only read of the value.

The corollary is the more interesting half, and it inverts the card's disposition:
those five sites already ignore a spec-compliant displayField / idField /
descriptionField / lookupFilters today. The user-serving change is to add the
declared camel reads, not to remove the snake ones. objectui#7435 already carries that
finding for two of the five; this census adds three more (deriveMasterDetail,
ListView's object-def branch, UserFilters).

3. The object-schema def and the widget bag are the same object at runtime

ObjectForm builds its fields from getObjectSchema and threads each def to the
widget. LookupField states this in-file ("the actual objectSchema field metadata ...
the form path is the real producer") and reads display_field / description_field /
id_field / lookup_filters snake-first. LookupFieldMetadata in
@object-ui/types — published, and documented as authorable in
content/docs/fields/lookup.mdx — declares all four.

This is the objectui#7155 shape exactly: the "no producer can emit it" argument is
true of the object contract and false of a second published one. Retiring the legs at
the object-schema consumers while the form widget keeps reading snake-first off the
same def would split one stored document's rendering between the form and the
chart, list, filters and action dialogs.

The census

site bag, traced to its producer contract camel leg? verdict
plugin-charts ObjectChart ds.getObjectSchema(schema.objectName), sole producer; the function is not in the package's public API object-schema def no KEEP
plugin-form deriveMasterDetail dataSource.getObjectSchema(d.childObject) in-repo, but deriveColumns is a public export so external bags are untraceable object-schema def in-repo, ambiguous outside no KEEP
plugin-list ListView, columns branch the view's own schema.columns ListColumnSchema, a third contract n/a, both castings refused KEEP
plugin-list ListView, object-def branch dataSource.getObjectSchema(...), sole producer object-schema def no KEEP
plugin-list UserFilters objectDef, a public prop typed loosely on a publicly exported component untraceable past this package no KEEP
app-shell resolveActionParams useMetadata().objects, the meta-API object documents object-schema def no KEEP
app-shell ObjectFieldInspector field def in the metadata-admin designer; writes camel back object-schema def yes, camel first KEEP

The card's table lists ListView as one site. It is two, on two different
contracts: the columns branch reads a list-view column, where ListColumnSchema
refuses display_field and displayField, id_field and idField,
reference_to and reference — measured, with a positive and a negative control.
That is objectui#7531's population, not this card's.

Measurements

FieldSchema.safeParse, installed spec, every control lit:

CONTROL A  {type,name,label}                          ACCEPTED   (instrument live)
CONTROL B  displayField / descriptionField /
           lookupFilters / reference                  ACCEPTED   (camel declared)
CONTROL C  zzz_not_a_real_key                         REJECTED unrecognized_keys
TEST       display_field / description_field /
           id_field / lookup_filters                  REJECTED unrecognized_keys

ListColumnSchema.safeParse, same controls: minimal column ACCEPTED, bogus key
REJECTED, and all ten keys tested (both castings) REJECTED with
unrecognized_keys.

ObjectSchema.fields is a record; an array is refused with
invalid_type: expected record, received array — noted because two of these sites
carry an Array.isArray(objectDef.fields) branch the object contract cannot produce.

One live disagreement, reported not fixed

The designer reads lookupFilters ?? lookup_filters (camel first) while the runtime
LookupField reads lookup_filters ?? lookupFilters (snake first), so a document
carrying both keys with different values is displayed one way and honoured the other.
Measured on main. PR #7641 is in flight and flips the runtime half, which retires
this disagreement on its own — so no card was filed for it.

Clause-2 determination

No — and it holds for the diff actually shipped, which is comments plus a
changeset. Worth recording, though, that the proposed retirement would not have been
Clause-2-no in the assumed way: because five sites carry no camel leg, removing the
snake reads would have removed the only read of four authorable keys, a user-visible
behaviour change rather than a dead-code deletion.

Verification

Gate union re-run at 09a2726a, the final commit:

check:control-bytes             exit 0   OK (scanned 6247 tracked text files)
check:designer-field-key-parity exit 0   designer-field-key-parity: OK
check-changeset-presence        exit 0   6 source files, 1 changeset, empty frontmatter
check-changeset-no-major        exit 0   no changeset declares a major bump
  • Dependency closure built, then type-check for app-shell, plugin-list,
    plugin-charts, plugin-form — all four echoed the script name (Scope: 4 of 47 workspace projects) and passed, so this is not a zero-match false green. The script
    in this repo is spelled type-check, not typecheck.
  • Targeted vitest from the repo root: 5 files, 107 tests, all passed.
  • eslint over the 6 changed files: 0 errors. The 303 warnings are pre-existing —
    0 lint messages land on any of the 44 added lines. The narrowing is a
    measurement, not a skip: file count read from --format json (6), and the flat
    config declares no project/projectService, so no file's verdict can depend on
    another file's contents.
  • Heavy runs went through the shared verify lock, slot issue-7642.

Scope

packages/types/**, plugin-grid/relationalMetaKeys.ts and the widget-metadata bag
were not touched. Verified zero file overlap with PR #7641's 30 files. reference_field
is reported on but not retired.

Labelled needs:contract-review on both carriers, as the dispatching ruling directs
when the census concludes a second published contract declares these spellings.


Generated by Claude Code

…object-schema snake-lookup census at each site, retiring none

Census only, no runtime change. Each of the six sites now carries the verdict for
the bag it actually reads, traced to its producer.

Three measurements moved every site to KEEP:

1. The serve path runs no parse. `ObjectStackAdapter.getObjectSchema` returns the
   server document verbatim plus `normalizeSchemaReferenceKeys` and
   `applyFieldWidgetOverrides` only, so a stored pre-strict document still delivers
   these keys. `FieldSchema`'s strictness gates authoring, not serving.
2. Five of the six sites have no camelCase leg, so retiring the snake read deletes
   the only read of the value rather than re-pointing it — and, conversely, those
   five already ignore a spec-compliant `displayField`/`idField`/`descriptionField`/
   `lookupFilters` today (objectui#7435 for two of them; this census adds three).
3. The object-schema field def and the widget bag are the same object at runtime:
   `ObjectForm` threads each `getObjectSchema` field def to the widget, where
   `LookupField` reads the snake spellings first and `LookupFieldMetadata` declares
   all four. Retiring here would split one stored document's rendering between the
   form and the chart/list/filter/action consumers.

One site of the six is not the object-schema def at all: `ListView`'s declared-columns
branch reads a list-view column, and `ListColumnSchema` refuses both castings of every
key involved (objectui#7531).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3180.3 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-C7hWyQsx.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 510.70KB 116.21KB
core (index.js) 6.70KB 2.68KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 180.00KB 50.20KB
fields (index.js) 242.40KB 61.26KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.98KB 10.98KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 48.04KB 13.35KB
plugin-charts (index.js) 70.92KB 19.75KB
plugin-chatbot (index.js) 196.19KB 46.43KB
plugin-dashboard (index.js) 132.86KB 34.68KB
plugin-designer (index.js) 212.86KB 43.19KB
plugin-detail (index.js) 250.59KB 64.06KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 132.87KB 32.66KB
plugin-gantt (index.js) 167.41KB 41.04KB
plugin-grid (index.js) 210.74KB 56.94KB
plugin-kanban (index.js) 52.71KB 14.55KB
plugin-list (index.js) 113.28KB 27.59KB
plugin-map (index.js) 20.57KB 6.82KB
plugin-markdown (index.js) 13.70KB 4.68KB
plugin-report (index.js) 43.57KB 11.96KB
plugin-timeline (index.js) 30.84KB 8.85KB
plugin-tree (index.js) 9.34KB 3.23KB
plugin-view (index.js) 85.24KB 20.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.58KB 2.23KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants