fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias) - #6963

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias
Aug 31, 2026
Merged

fix(components)!: data-table reads only the declared accessorKey (retire the col.name alias)#6963
os-zhuang merged 2 commits into
mainfrom
claude/issue-5120-retire-data-table-name-alias

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#5120

Last step of the 2026-08-20 maintainer ruling on the column-alias family: the
data-table adapter now reads only the declared accessorKey, and the two
published skill guides that taught the undeclared name spelling migrate in
the same commit.

Three-quarters of this card already landed (#5353 producer identity, #5478
label retirement + columnHeader, #5350 the static table renderer). This is
the held quarter.

⛔ Governed surface — human merge only

The diff touches skills/**. check:governed-queue-guard --test on this exact
file list answers, mechanically:

⛔ GOVERNED — 2 of 7 path(s) are on a governed surface:
skills/** x2 — the published skills catalog

So this PR stays draft. Not marked ready, not enqueued, no auto-merge. The
merge-queue guard refuses it without an approval from GOVERNED_APPROVERS
(os-zhuang, hotlong) pinned to the current head. Card #5120 additionally
carries needs:contract-review (the label sits on the card, not on this PR);
that review has since returned ACCEPT-WITH-CONDITIONS, and both conditions
are addressed in 8be968586.

What changed

packages/components/src/renderers/complex/data-table.tsx — both
accessorKey: col.accessorKey || col.name reads, found by content at
:870 and :882 (the ruling's :777/:786 are from 2026-08-18 and had
shifted twice; they now sit at :875/:887 after the docblock rewrite).

skills/objectui/guides/data-integration.md and schema-expressions.md — the
4 column entries move { name, label }{ header, accessorKey }, matching
the declared spelling schema-expressions.md already teaches for table.

Blast radius — adapter-only, and bounded by measurement

A { name, label } column arriving through ObjectDataTable, RelatedList or
ObjectGrid is unaffected
— but for two different reasons, and contract
review caught me conflating them (condition 1, corrected in 8be968586):

The conclusion — unaffected — holds for all three. The mechanism held for two.
Worth a commit rather than a shrug: the 2026-08-20 ruling's item 2 told
ObjectGrid to "connect to the same columnIdentity resolution", #5478 measured
that following it would have re-widened what #5068 narrowed, and the claim
has now been restated in the wrong direction by two separate seats. A third
repetition is how it becomes settled fact, so it is corrected in the changeset
(author-facing, and the copy that would otherwise ship into release notes) and
in the two test comments that carried it.

What narrows is a column authored directly onto a data-table node.

That bound is now a test, not a claim — a PRODUCER-resolved column is unaffected — the narrowing is adapter-only.

It is also why the related[] example in content/docs/api/schema-reference.md
(a detail-view related list of type: "table", { name, label } columns) does
not break: it reaches data-table through RelatedList, which resolves it. That
file is left byte-untouched (verified by blob hash), as is
renderers/complex/table.tsx.

Census — pathspec bound stated, hot control carried

Two independent methods, both counter-probed.

Method 1 — bracket-matched extraction of every columns: [...], split into
top-level entries, each classified by its enclosing node's type.

boundpopulationname-spelled data-table columns
dispatch pathspec — examples/ (482), content/docs/ (204), apps/ (231), skills/ (29), e2e/ (31), packages/*/README.md (43)1,020 tracked files4
repo-wide — all tracked text files5,598 tracked files4

Same 4 at both bounds, all in the two adjudicated guides. Zero outside them.

  • Hot control (required): PASSED — the census found exactly the 4 known
    entries. A zero elsewhere is therefore a reading, not a broken search.
  • Second control: 129 declared accessorKey entries found repo-wide, so the
    instrument sees both spellings.

Other name-spelled buckets are other vocabularies and were adjudicated, not
waved past: grid (26 — name is its declared field key), table (7 —
separate renderer, #5350), crud (7 — no registered renderer), list (5),
untyped form/report arrays (84 — fields[], master-detail, Excel export).

Method 2 — enumerate every file containing a data-table node, then read
its column spellings directly. Same answer. It also cleared the two files whose
raw name counts looked suspicious: skills/objectui/rules/protocol.md (its
name keys are a flow action's fields[], and its data-table blocks use
"columns": [...] as an ellipsis) and content/docs/utilities/vscode-extension.mdx
(a form field and a bar-chart data row).

The prior measurement was re-measured, and it has changed

The 2026-08-21 reading was: label retired + name held = 15/15 green;
retiring name = 2 red.

Reverse verification — direction predicted before each run

No build artifact sits between edit and test: root vitest.config.mts aliases
every @object-ui/* specifier to that package's src/ (read out of the config,
:274-303, not assumed). Each leg mutated from the committed state, proved
the mutation on disk by grep counts of injected and deleted text plus a blob
hash differing from the HEAD blob, ran, then restored with
git checkout HEAD -- PATH and proved restoration by git diff HEAD empty
and blob hash identical to HEAD. Both legs carried an absolute-path
trap … EXIT INT TERM.

Leg 1 — alias restored, everything else kept. Predicted 2 red by name;
observed exactly those 2, 28 green:
does not resolve an accessor from 'name', LEGIBILITY: an unresolvable column keeps its header and spares its neighbour. The guide gate stayed 16/16
green
— the asymmetry that matters: once the guides spell accessorKey, they
render with or without the alias.

Leg 2 — guides reverted, alias kept retired. Predicted 3 red by name;
observed exactly those 3, 27 green: my new spelling assertion plus the two
the inline-'data' table puts its rows on screen cases. This is the
re-measurement of the prior "2 red" split.

One honest miss: an annotation on leg 2 predicted remaining(declared)=1 and
observed 0 — my fixed-string probe carried a trailing comma the pre-existing
:513 example does not have. The load-bearing injected=2 assertion held.
Reported as observed rather than trimmed.

Tests

At 7538f0ac3, clean tree, from the repo root (a package-scoped run uses a
different config than CI):

  • packages/components219 files / 2014 tests passed
  • packages/plugin-dashboard + plugin-detail + plugin-grid + core
    404 files / 4874 tests passed (the producer direction; predicted green,
    observed green)
  • pnpm --filter '@object-ui/components' type-check — exit 0, script echoed by
    name. It runs tsc -p tsconfig.test.json too, and --listFiles confirms all
    3 edited test files are in that file set — measured, so "typecheck clean"
    really covers the edits.
  • eslint on the 4 changed .ts/.tsx files — 0 errors, 35 pre-existing style
    warnings (no-explicit-any ×24 etc.).

Lint narrowing, declared with its evidence (rather than a repo-wide run):
① the 2 guide .md files are outside eslint's population — eslint says so
itself, File ignored because no matching configuration was supplied;
--format json reports 4 files judged; ③ type-aware linting is off
(--print-configparserOptions: {}, no project/projectService), so this
diff cannot move the verdict on any untouched file.

Gate union re-run at 7538f0ac3 on a clean tree, all exit 0:
check:skills-paths · check:doc-types · check:doc-fences ·
check:control-bytes (5,785 files) · check:self-import · check:phantom-deps ·
check:esm-specifiers · check:vi-mock-specifiers · check:governed-queue-guard ·
check:doc-snippets (271/271 blocks judged, 0 failed).

⚠️check:doc-snippets first exited 2, which is not a red gate — its own
verdict line says PRECONDITION NOT MET … The snippet program was NOT run. Built
what it names, re-ran, green. Recorded so the 2 is not read as a failure.

The ruling clause that contradicts the tree — reported, not silently dropped

The ruling's item 2 says all three producers "connect to the same columnIdentity
resolution", naming ObjectGrid. #5478's dev measured that ObjectGrid must not
(it would re-widen what #5068 narrowed), and the dispatching seat accepted that
correction. This PR implements the ruling's direction and does not touch
ObjectGrid — consistent with that accepted correction, and recorded here so the
next reader does not re-derive the wrong action.

Changeset

minor, graded and justified in the file itself: this narrows the accepted
input set
, which is breaking for any author who used the tolerated spelling —
so it is not patch, and it is written in author-facing terms with the
before/after and the recognisable failure shape (live header over blank cells),
not as "internal cleanup". Not major, per this repo's fixed-group convention.

Also corrected here

skill-guide-data-table-binding.test.tsx's docblock claimed it "stays true
whichever way #5120 lands — nothing below asserts a column key spelling". That
was false (filed as #5479): its assertions are on rendered cell text, so
they transitively pin the accessor spelling. This is the coupling that made this
step invisible when the family was ruled on. Corrected, and an explicit spelling
assertion added so the failure names the key and the card instead of diffing
two cell arrays.


Authored by Claude Code in session
https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB (recorded in prose
because editing a PR body rewrites the footer's session form).

Generated by Claude Code


Generated by Claude Code

Retire the undeclared `col.name` tolerance on the data-table adapter, and
migrate the instruction corpus that taught it in the same commit.
`data-table`'s column normalization read `accessorKey: col.accessorKey ||
col.name` at two sites, but `TableColumn` (`@object-ui/types`) declares only
`accessorKey`. The declared surface admitted one spelling while the runtime
admitted two — the second de-facto contract AGENTS.md #0.1 forbids. The
maintainer ruling of 2026-08-20 settled the direction for the family: retire
the consumer-side alias, translate at the producers. `label` retired first;
this closes the family.
The two published skill guides that taught `{ name, label }` columns migrate
to the declared `{ header, accessorKey }` here, not in a follow-up. They are
executable fixtures — `skill-guide-data-table-binding.test.tsx` lifts their
fenced JSON at run time and renders it — so moving the runtime without the
instruction would leave the platform refusing a spelling it still ships.
Blast radius is adapter-only: columns arriving through ObjectDataTable,
RelatedList or ObjectGrid are unaffected, because each producer folds `name`
into `accessorKey` via `columnIdentity` before delivery. What narrows is a
column authored directly onto a `data-table` node.
Tests follow the change rather than being retrofitted to it:
- the HOLD pin in `data-table-declared-column-keys.test.tsx` becomes a
retirement pin, plus a legibility pin (live header over blank cells,
neighbour untouched) and a producer-resolved pin bounding the radius;
- the guide gate's docblock claimed it "stays true whichever way #5120
lands — nothing below asserts a column key spelling". That was false
(objectui#5479): its assertions are on cell text, so they transitively pin
the accessor spelling. Corrected, and an explicit spelling assertion added
so the failure names the key and the card instead of diffing cell arrays;
- `skill-guide-provider-envelope.test.tsx` carried a hardcoded `{ name,
label }` COLUMNS fixture mirroring the guides; migrated with them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

… fold it
Contract review on PR #6963 caught a mechanism mis-attribution. The
blast-radius CONCLUSION was verified correct — columns arriving through
ObjectDataTable, RelatedList or ObjectGrid are all unaffected by the
`col.name` retirement — but the stated REASON held for only two of the three.
- ObjectDataTable and RelatedList genuinely resolve the legacy spelling,
stamping `accessorKey` from `columnIdentity(col)` before delivery.
- ObjectGrid does NOT fold. Since #5068 it refuses undeclared spellings at
intake: `resolvesToDataColumn` requires a non-empty string `field`, so a
name-spelled entry is dropped before delivery and never reaches the adapter
at all — before and after this PR. What it delivers carries `accessorKey`
stamped from `field`.
This matters beyond pedantry: the 2026-08-20 ruling's item 2 told ObjectGrid to
"connect to the same columnIdentity resolution", and #5478 measured that
following it literally would have re-widened exactly what #5068 narrowed. The
claim has now been restated in the wrong direction by two separate seats. A
third repetition is how it becomes settled fact, so it is corrected in the
durable artifacts rather than only in a review thread.
Corrected in the changeset (author-facing, and the one that would have shipped
the false mechanism into release notes), and in the two test comments that
carried it. Comment and changeset text only — no assertion, no source line, and
no behaviour changes; the three affected pin files stay 44/44 green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3179.9 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-c1ZLM87v.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)12.46KB4.71KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)175.69KB48.80KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)76.75KB25.49KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:30
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 4172589Aug 31, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5120-retire-data-table-name-alias branch August 31, 2026 07:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude