Skip to content

ReportView reads only the declared dataSource.object key - #5488

Merged
os-support-ai merged 3 commits into
mainfrom
claude/issue-5116-reportview-resource-alias
Aug 21, 2026
Merged

ReportView reads only the declared dataSource.object key#5488
os-support-ai merged 3 commits into
mainfrom
claude/issue-5116-reportview-resource-alias

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#5116

ReportView accepted resource as a second spelling of object on a report's dataSource binding, in two places, and named that spelling in a warning the user could read:

:171 liveReport?.objectName || liveReport?.dataSource?.object
|| liveReport?.dataSource?.resource
:273 dataFetchSource.dataSource.object || dataFetchSource.dataSource.resource
:275 console.warn('ReportView: dataSource missing object/resource property')

resource is not on this contract. ElementDataSourceConfig declares object / view? / filter? / sort? / limit?; its spec twin ElementDataSourceSchema is a strict object, so an extra resource key is rejected there rather than ignored; and the binding's predicate isElementDataSourceConfig decides on object. A resource-only binding was therefore never a binding on any other renderer — it rendered here and silently produced nothing everywhere else, with neither end reporting a problem.

resource is a real key on other surfaces — CRUDSchema.resource, the DataSource adapter's first parameter, LiveExportOptions.resource — all three untouched. None of them is this one.

Per AGENTS.md #0.1 an off-spec spelling is corrected at the producer, never taught a second dialect by the renderer.

Producer census (premise-first), with counter-probe

Triage asked this be re-verified on current main before deleting: if any producer or authored site supplies resource on this binding, the card becomes a migration, not a tolerance deletion. Result: zero producers.

probeobjectuiobjectstack (framework)
dataSource block containing resource0 real hits0 hits
counter-probe — same regex, object instead182 hits15 hits

The counter-probe is what makes the zero a reading rather than a broken search: the identical multiline pattern finds 182 + 15 sites for the key that is produced.

Authored corpora were searched too, not just source — docs (content/docs/**), skills/**, examples, fixtures, and every .json / .yaml / .md / .mdx. Every authored resource: key found resolves to a different surface, individually inspected:

  • packages/plugin-report/README.md:412LiveExportOptions.resource, an argument to exportWithLiveData, beside the runtime adapter
  • content/docs/api/schema-reference.md:532CRUDSchema.resource (type: 'crud')
  • content/docs/guide/objectos-integration.mdx:284useViewData({ resource }) hook options
  • packages/core/src/adapters/README.md:33 — a sibling key of dataSource on a data-table schema, not dataSource.resource
  • packages/permissions/README.md:108evaluatePermission({ resource })
  • the remaining ~770 tokens are DataSource method parameters, plugin-gantt's resource-workload feature, etc.

The two multiline hits inside a dataSource block are both the adapter interface declaring create(resource: string, ...) / update(resource: string, ...) — method parameters, not a metadata key.

History: git log -S traced the limb to the commit that first added data loading to this view. It was speculative in that commit — no producer preceded it, and none appeared since. The three report fixtures in examples/schema-catalog carry no dataSource at all.

The premise holds, so the deletion proceeds rather than escalating.

Behaviour, measured by rendering

Each input shape was rendered through the real component before and after, reading the actual adapter query, the rows handed to the renderer, the config panel's field list, and the warning. The resource-only cases put a real object (acct, with real fields) behind the non-contract spelling, so "not queried" proves the spelling was not read, not that there was nothing to read.

bindingbeforeafter
{ object: 'acct' }queries acct, 1 row, fields industryunchanged
{ resource: 'acct' }queries acct, 1 row, fields industry, no warningnot queried, 0 rows, fallback fields, warns ReportView: dataSource missing object property
{ object: 'acct', resource: 'other' }queries acct, fields industryunchangedresource was already inert
{}not queried, 0 rows, fallback fields, warns missing object/resource propertynot queried, 0 rows, fallback fields, warns missing object property

The behaviour being removed, stated plainly: a resource-only report binding used to render as if declared. It now fails loudly — a named warning, zero rows, and the fallback field list — instead of appearing to work while every other renderer in the system disagreed with it. Only that one shape moves; the other three are byte-identical readings.

The :275 wording now names only object. A diagnostic listing a key the contract does not declare is not cosmetic: it is the system telling an author — increasingly, an author's code generator — that the wrong spelling is supported.

Reverse-verification

Both legs were run from the committed state, direction predicted before running.

legablationpredictedobserved
1restore origin/mainReportView.tsx (both limbs + old wording)RED, 3 failed / 2 passed; resource only, neither, warning names objectexact matchexpected 'acct' to be null, missing object/resource property, expected '' to contain 'object'
2restore only the two `` limbs, keep the reworded warning

Leg 2 is what separates the two halves of the fix: it shows each assertion is load-bearing for a specific limb, and that neither is the assertion pinning the :275 reword.

Ablation validity: this package's tests resolve the component through a relative source import (./ReportView) and the root vitest alias table maps every @object-ui/* specifier to src/ — so the mutation is read straight from source with no dist/ in the path. Demonstrated rather than assumed: the source-only edit moved the suite red and back green with no rebuild between.

Restored afterwards and proven clean by blob hash, not by eyeball — worktree 13466eff4fc346c70267b5c2f44a3a9c910062b1 equals the committed blob, git status empty.

Verification at d8a61a5ce

The gate union below was run after the final commit, on that sha.

  • pnpm exec vitest run packages/app-shell/src/views/285 files, 2817 passed, 1 skipped (the skip is a pre-existing spec-version skipIf in flow-node-config.spec-reconciliation.test.ts, untouched)
  • pnpm exec vitest run packages/app-shell/src/console/ packages/app-shell/src/__tests__/59 files, 500 passed (the route + barrel that consume ReportView)
  • new pin ReportView.dataSourceObjectKey.test.tsx5/5
  • pnpm --filter @object-ui/app-shell type-check — clean (tsc --noEmit && tsc -p tsconfig.test.json, script name echoed; 3 real type errors in the new test were found and fixed here, not suppressed)
  • eslint on both changed files — 0 errors. ReportView.tsx warning count is 24 before and 24 after, measured against an origin/main copy — zero introduced
  • check:control-bytes, check:esm-specifiers, check:self-import, check:phantom-deps, check:doc-types — pass
  • check:doc-snippets — pass, after building the packages it resolves against; its own sentinel/positive controls are green, so this is a real reading rather than a skipped one
  • check:eager-closure (ratchet) — pass: 3792.5 KB gzipped, budget 3867.2 KB, 74.7 KB headroom. Required building apps/console and its closure; ReportView stays lazily routed, and no import statement changed
  • check-changeset-presence, check-changeset-no-major — pass

No test skipped, disabled, or quarantined.

Notes

  • Changeset: minor, declaring the removal honestly with the per-shape table. Not major — per AGENTS.md that would drag the whole 39-package fixed group off the @objectstack major it tracks.
  • Small rename in the same hunk: the local resource variable at the fetch site is now objectName. It was the last in-code echo of the non-contract spelling on the very line being fixed, and an open invitation to re-add the alias. The adapter's own parameter is still called resource; a comment records where the two vocabularies meet.
  • Scope: three files. #5203 is in flight in this same package but confined to layout/ and hooks/neither directory is touched, verified against the merge base. No governed surface (AGENTS.md, CLAUDE.md, .claude/**, docs/adr/**, skills/**) is touched.
  • No out-of-scope findings surfaced; nothing was filed.

Generated by Claude Code

…` key
`ReportView` accepted `resource` as a second spelling of `object` on a
report's `dataSource` binding, in two places, and NAMED that spelling in a
user-facing warning:
:171 liveReport?.objectName || liveReport?.dataSource?.object
|| liveReport?.dataSource?.resource
:273 dataFetchSource.dataSource.object || dataFetchSource.dataSource.resource
:275 console.warn('ReportView: dataSource missing object/resource property')
`resource` is not on this contract. `ElementDataSourceConfig` declares
`object` / `view?` / `filter?` / `sort?` / `limit?`, its spec twin
`ElementDataSourceSchema` is a strict object (an extra `resource` key is
rejected, not ignored), and `isElementDataSourceConfig` decides on `object` —
so a `resource`-only binding was never a binding anywhere else. `resource` is
a real key on OTHER surfaces (`CRUDSchema.resource`, the `DataSource` adapter's
first parameter, `LiveExportOptions.resource`); none of them is this one.
Per AGENTS.md #0.1 an off-spec spelling is fixed at the producer, never as a
renderer-side alias — and a producer census found nothing to fix: no site in
this repo or in the `objectstack` framework repo writes `resource` onto a
report `dataSource`. The limb was speculative in the commit that added it.
Measured by rendering, per input shape (before -> after):
object only queries `acct` -> queries `acct` (unchanged)
resource only queries `acct` -> not queried, warns (REMOVED)
object+resource queries `acct` -> queries `acct` (unchanged)
neither not queried -> not queried, warns (unchanged)
A `resource`-only binding now fails loudly (named warning, empty rows,
fallback field list) instead of rendering off-spec metadata as if it were
valid. The `:275` wording names only `object`, so the diagnostic no longer
promises a key the contract does not declare.
The local `resource` variable at the fetch site is renamed `objectName` — it
was the last in-code echo of the non-contract spelling at the very line being
fixed, and an open invitation to re-add the alias. The adapter's own parameter
is still called `resource`; a comment records where the two vocabularies meet.
Fixes#5116
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
Behaviour removal, declared honestly: a `resource`-only report binding used to
render and now does not. Marked `minor` per AGENTS.md (objectui's own breaking
semantics never take `major` — that would drag the whole fixed group off the
`@objectstack` major it tracks); the breaking semantics are spelled out in the
changeset body along with the per-shape before/after table.
Part of #5116
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
`tsc -p tsconfig.test.json` rejected three spots in the new pin: an untyped
`vi.fn()` gave `mock.calls` an empty tuple type, so reading the captured first
argument was both an impossible cast and an out-of-range index, and the warn
spy's callback parameter was implicitly `any`.
The spy now declares the real `DataSource.find(objectName, params)` signature,
which makes the captured argument a `string` with no cast at all — the
assertion reads the query the way the adapter would receive it.
Part of #5116
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3781.2 KB3867.2 KB
Main entry chunk (gzip)151.2 KB350 KB
Entry fileindex-CESQ7OZT.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 (index.js)10.04KB3.72KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)29.34KB7.05KB
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)6.35KB2.43KB
auth (index.js)2.77KB1.22KB
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.02KB0.89KB
auth (useIsWorkspaceAdmin.js)3.04KB1.45KB
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)506.94KB113.63KB
core (index.js)4.11KB1.62KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)159.80KB44.34KB
fields (index.js)237.21KB59.50KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.22KB3.08KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)30.51KB7.57KB
i18n (useSafeTranslation.js)7.77KB3.13KB
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)9.35KB3.31KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.42KB1.42KB
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)1.81KB0.83KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.75KB18.37KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)128.51KB32.94KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)242.15KB60.89KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)124.40KB30.26KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)200.75KB54.24KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.64KB27.13KB
plugin-map (index.js)20.08KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.52KB20.67KB
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)3.77KB1.33KB
react (SchemaRenderer.js)36.10KB12.26KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.33KB0.69KB
react (schema-input.js)1.45KB0.83KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (index.js)4.77KB2.16KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)10.76KB3.17KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)6.92KB2.40KB
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)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.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-retry.js)4.32KB2.02KB
types (index.js)3.08KB1.53KB
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 (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
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-support-ai
os-support-ai marked this pull request as ready for review August 21, 2026 03:27
@os-support-ai
os-support-ai added this pull request to the merge queueAug 21, 2026
Merged via the queue into main with commit 60d452eAug 21, 2026
23 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-5116-reportview-resource-alias branch August 21, 2026 03:28
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants

@os-support-ai@claude