Skip to content

fix(plugin-view): spell the views-prop sort direction key order, not direction - #6008

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-5293-viewsort-order-spelling
Aug 24, 2026
Merged

fix(plugin-view): spell the views-prop sort direction key order, not direction#6008
yinlianghui merged 2 commits into
mainfrom
claude/issue-5293-viewsort-order-spelling

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Fixes#5293

Implements the maintainer ruling of 2026-08-24 (Route 2), verbatim: 「四维分析一致的,接手你的建议。」

ObjectViewProps.views[].sort declared { field, direction } while every consumer of the resolved activeView.sort reads order. The key is renamed to order, matching every other sort surface in the repo and the shared sink. Verification union run at 604c2036.

Why the break costs nothing

Nothing has ever read direction. Re-derived on the current tree rather than trusting the card (which was verified at 12841b617, five days stale — line numbers had all moved and one consumer had changed mechanism):

consumerreadsa direction entry yields
non-grid fetch (ObjectView.tsx:786)convertSortToQueryParams(sort), whose entry.order === 'desc' is false for a missing key{ name: 'asc' }
grid path (:1364)ObjectGridSchema.sort`${s.field} ${s.order}`wire string "name undefined", and parseSchemaSort draws an ascending arrow
mergedSort (:1499)forwarded to the delegated list viewunchanged

A host writing the exact shape the prop declared got an ascending list with no failure signal. The rename converts a silent wrong answer into a loud type error. That framing is in the changeset, which names the retired spelling so an external host can search for it.

Note the card's stated mechanism for the first consumer no longer holds: #4869 landed, so the non-grid fetch now lowers through the shared sink instead of passing $orderby raw. The outcome is identical (entry.order is equally absent), so the conclusion survives — but it was re-measured, not assumed.

⛔ Not a tolerant dual-read

No direction ?? order anywhere. That is the tolerance layer #4869 ruled against. A @ts-expect-error guard in ObjectView.sortSink.test.tsx now turns red if the old key is ever readmitted, so the prohibition is mechanically enforced rather than only documented.

The ruling's producer list was wrong in one place — corrected here

The ruling named two in-repo direction producers. Measured against the tree, one is misattributed and two more exist:

  • packages/app-shell/src/views/view-config-adapter.test.ts (:18, :82) — round-trip fixtures, corrected. PM assumption 2 confirmed: view-config-adapter.ts itself has 0 hits for direction (sort?: unknown[]), and the round-trip asserts expect(back.sort).toEqual(view.sort), so it is spelling-agnostic behaviourally as well as by type. Blast radius is as the ruling priced it.
  • packages/plugin-view/src/index.tsx:177 — NOT touched, the ruling misattributed it. That defaultProps block belongs to ComponentRegistry.register('sort-ui', SortUI, …) (the enclosing register call opens at :158), i.e. it is SortUI's own default, where direction is type-correct: SortUISchema.sort declares direction: 'asc' | 'desc' (packages/types/src/views.ts:862-871) and SortUI.tsx:188/:207 read singleSort.direction at runtime. Renaming it would have broken SortUI and contradicted PM assumption 3, which forbids touching that surface. The ruling's producer list and its own do-not-touch note were in conflict; the note is the half that is right.
  • packages/plugin-view/src/__tests__/ObjectView.sortSink.test.tsx:208 — not named by the ruling. This held a pin written for this card asserting $orderby equals { name: 'asc' } for a direction: 'desc' fixture — green only because nothing read the key, with a comment saying "Pinned so that whoever DOES fix that card is told this site exists." Fixture-triage case: replaced, not re-spelled, because it pinned the very branch being removed.
  • packages/plugin-view/src/__tests__/ObjectView.test.tsx:490 — not named by the ruling; would have become a hard type error.

The last two are taken under the bounded in-place exemption (same defect class, mechanical with the correct form pinned by the ruling, no other claim on packages/plugin-view/**, same gate family), and are named here rather than folded in silently.

Reverse verification — direction predicted before running, and one prediction was wrong

Type leg (revert the declaration to direction): predicted red, observed red — 3 errors, exit 2. The interesting one is inverted, which is what makes the guard non-vacuous:

sortSink.test.tsx(207,84): error TS2353: ... 'order' does not exist in type '{ field: string; direction: "desc" | "asc"; }'.
sortSink.test.tsx(227,9): error TS2578: Unused '@ts-expect-error' directive.
ObjectView.test.tsx(494,65): error TS2322: ... not assignable ...

TS2578 proves the @ts-expect-error is genuinely suppressing a real error under the fix.

Runtime leg: predicted red, observed green (12/12 passed) — the prediction was wrong, and the reason is sound. The declaration is type-only, so reverting it cannot change runtime; TypeScript is erased. Reported rather than dressed up: enforcement of this fix lives entirely at the type boundary.

To show the runtime assertion is not vacuous, the falsifying mutation is the fixture, not the declaration — swapping its key back to direction fails with exactly the bug shape:

AssertionError: expected { name: 'asc' } to deeply equal { name: 'desc' }

Every mutation was confirmed on disk by grepping the injected and removed text separately (an editor's exit code proves nothing on a zero-hit anchor), and each leg ran under a trap … EXIT INT TERM restore. Tree confirmed byte-identical to HEAD afterwards. No rebuild was needed for either leg: the suite imports ../ObjectView relatively, so the subject resolves from source, not through the package's exports/dist.

Verification, run at 604c2036

gateverdict line
type-check@object-ui/plugin-view (tsc --noEmit && tsc -p tsconfig.test.json)exit 0, script name echoed
type-check@object-ui/app-shellexit 0
type-check@object-ui/console (downstream)exit 0
vitest run packages/plugin-view/src + adapter suite23 files / 223 tests passed

Downstream direction stated: the contract narrowed, so consumers were swept with the prefix form pnpm --filter '...@object-ui/plugin-view'app-shell, console, site, and three private examples. app-shell and console typecheck clean; examples/ and apps/ were swept for the retired spelling and contain no producer of it.

Both packages' first typecheck was red with Cannot find module '@object-ui/…' — the unbuilt-closure signature, not a real failure; green after building each package's dependency closure with the suffix filter form (PKG^...). Recorded because that red reads exactly like a broken import.

Lint — narrowed, and the narrowing is measured. The repo-wide eslint . is CI's run. Locally: eslint's own config linted 4 of 4 changed source files (count read from --format json, none ignored); 0 errors, 88 warnings; and the identical run at the merge-base 8d3a5294a gives 0 errors, 88 warnings — delta 0/0, so every warning is pre-existing. Untouched files are invariant because no type-aware linting is configured (no project / projectService in eslint.config.*), so this diff cannot move another file's verdict.

Out of scope, filed separately

#6006 — the published skill skills/objectui/guides/data-integration.md teaches a QueryParams shape the adapters silently drop: the sort key spelled direction (same defect class as this card, different surface), and every query option written without its $ prefix — the class #5458 fixed in repo code, where an unprefixed key "reaches no branch and is dropped". Not fixed here: different surface, and skills/** is a customer-published package with its own expansion-budget discipline that this dispatch carried no budget for.

Also left alone deliberately, each a different surface rather than an instance of this defect: packages/types (ExportDownloadRequest.sort, designer.ts, data-protocol.tsorderBy — and claimed by a concurrent sibling), the export-boundary conversions in ObjectGrid.tsx:2089 and ListView.tsx:2520 (both convert fromorder), and ObjectView.filterSources.test.tsx:161 (table.defaultSort).

Changeset: minor per AGENTS.md §版本号策略 — objectui ships its own breaks as minor, never major (CI-enforced by check-changeset-no-major.mjs).


Generated by Claude Code

…t `direction`
`ObjectViewProps.views[].sort` declared `{ field, direction }` while every
consumer of the resolved `activeView.sort` reads `order` — the shared sink
`convertSortToQueryParams`, the grid path via `ObjectGridSchema.sort`, and
`mergedSort`. A host writing the exact shape the prop declared got a silently
ascending list with no failure signal anywhere.
Renaming the key to `order` gives the repo one sort spelling and makes the
retired one a loud type error. Per the 2026-08-24 maintainer ruling this is
deliberately NOT a tolerant dual-read (`direction ?? order`) — that is the
tolerance layer objectui#4869 ruled against.
Producers corrected: the studio adapter round-trip fixtures, and two
`views`-prop fixtures inside plugin-view's own suite that the ruling did not
enumerate. `ObjectView.sortSink.test.tsx` held a pin asserting `{ name: 'asc' }`
for a `direction: 'desc'` fixture — green only because nothing read the key —
which is replaced by an assertion that the direction now survives, plus a
`@ts-expect-error` guard that turns red if the old spelling is ever readmitted.
NOT touched: `SortUI` and its `sort-ui` `defaultProps` in `index.tsx`, which
legitimately own `direction` on their own `SortUISchema`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3232.9 KB3990.2 KB
Main entry chunk (gzip)153.6 KB350 KB
Entry fileindex-8RqDMlaT.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)10.38KB3.90KB
app-shell (runtime-config.js)18.10KB6.51KB
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)504.91KB114.42KB
core (index.js)4.92KB1.97KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)165.30KB45.79KB
fields (index.js)238.40KB59.89KB
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.62KB3.26KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
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.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
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.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.21KB44.67KB
plugin-dashboard (index.js)133.35KB34.44KB
plugin-designer (index.js)212.30KB42.80KB
plugin-detail (index.js)244.14KB61.88KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)125.63KB30.64KB
plugin-gantt (index.js)164.15KB39.88KB
plugin-grid (index.js)200.79KB54.26KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.86KB27.22KB
plugin-map (index.js)20.10KB6.64KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.57KB20.74KB
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)52.40KB17.45KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
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)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
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)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-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (index.js)4.13KB1.96KB
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

… prop
The changeset and the `ObjectViewProps.views` JSDoc both carried an
unqualified repo-wide negative — "no reader in the repo has ever known the
word" — that one grep in this same package falsifies: `toSortItems`
(`src/config/view-config-utils.ts:328`) folds `s.order || s.direction ||
'asc'`, and it is a published export (barrel `src/index.tsx:38`, README:91).
The scoped claim in the same paragraph — all three consumers of the resolved
`activeView.sort` read `order` — is the one that carries the argument and is
correct. Both artifacts now make that claim instead, and both name the
surviving site so a host migrating `views[].sort` who greps the old key does
not read the hit in `toSortItems` as a partial retirement.
Retiring that fallback is its own break on its own public export and is
tracked separately; it is deliberately untouched here.
Prose only: no declaration, no fixture and no runtime line changes. The
`views[].sort` declaration, the `@ts-expect-error` guard and the whole code
half of this branch are byte-identical to the previous commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3232.9 KB3990.2 KB
Main entry chunk (gzip)153.6 KB350 KB
Entry fileindex-8RqDMlaT.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)10.38KB3.90KB
app-shell (runtime-config.js)18.10KB6.51KB
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)504.91KB114.42KB
core (index.js)4.92KB1.97KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)165.30KB45.79KB
fields (index.js)238.40KB59.89KB
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.62KB3.26KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
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.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
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.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.21KB44.67KB
plugin-dashboard (index.js)133.35KB34.44KB
plugin-designer (index.js)212.30KB42.80KB
plugin-detail (index.js)244.14KB61.88KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)125.63KB30.64KB
plugin-gantt (index.js)164.15KB39.88KB
plugin-grid (index.js)200.79KB54.26KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.86KB27.22KB
plugin-map (index.js)20.10KB6.64KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.57KB20.74KB
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)52.40KB17.45KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
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)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
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)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-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (index.js)4.13KB1.96KB
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

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

Rework pushed — prose only, 54ee7f05b

Head moved 604c2036654ee7f05b. One commit, no code change: every changed line is a JSDoc continuation line or changeset prose. The views[].sort declaration, the @ts-expect-error guard, both corrected fixtures and the adapter fixtures are byte-identical to the previous commit (git diff 604c20366..54ee7f05b touches exactly .changeset/5293-view-sort-order-spelling.md and the ObjectViewProps.views JSDoc block).

What changed and why. The changeset and the JSDoc both carried an unqualified repo-wide negative — "no reader in the repo has ever known the word" — that one grep in this same package falsifies: packages/plugin-view/src/config/view-config-utils.ts:328 folds s.order || s.direction || 'asc' inside toSortItems, a published export (barrel at src/index.tsx:38, documented at README.md:91). Both artifacts now make the scoped claim instead — all three consumers of the resolved activeView.sort read order — and both name the surviving site, so a host migrating views[].sort who greps the old key does not read that hit as a partial retirement.

That site is unreached from this prop and is not retired here. It is filed as #6011 (unassigned, no labels) with its own option analysis, since removing a tolerant read from a published export is its own break needing its own adjudication. #6011 also records ObjectView.filterSources.test.tsx:161-162 as a related stale-spelling fixture: it writes direction on table.defaultSort, a surface that declares order (packages/types/src/objectql.ts:673-676), behind an as any, and stays green only because that test asserts verbatim pass-through.

Union re-run at 54ee7f05b (supersedes the 604c2036 citation in the body above for these two gates):

gateverdict line
pnpm --filter @object-ui/plugin-view type-checkexit 0, script name echoed (> @object-ui/plugin-view@17.6.0 type-check), runs tsc --noEmit && tsc -p tsconfig.test.json
pnpm exec vitest run packages/plugin-view/src --maxWorkers=2Test Files 22 passed (22) / Tests 217 passed (217), exit 0
pnpm changeset:checkexit 0 — "All workspace packages are in the changeset fixed group" / "No changeset declares a major bump"
pnpm check:control-bytesexit 0 — "OK (scanned 4971 tracked text file(s); skipped 85 binary)"

No test verdict moved, and the accounting is exact rather than eyeballed: the previous round ran packages/plugin-view/srcpluspackages/app-shell/src/views/view-config-adapter.test.ts and reported 23 files / 223 tests; that adapter file declares 6 tests, so 23−1 files and 223−6 tests is precisely this round's 22 / 217. The adapter fixtures are untouched by this commit.

Lint delta measured, not assumed. eslint's own config linted 1 of 1 changed source file (the changeset .md is not in eslint's set), count read from --format json, none ignored: 0 errors / 59 warnings at 54ee7f05b, and 0 errors / 59 warnings for the same file at 604c20366 — delta 0/0. Untouched files are invariant because no type-aware linting is configured (no project / projectService in eslint.config.*). The baseline leg checked the old file out, measured, and restored from the commit, with the injected text grepped at 0 before and 1 after; git status --porcelain empty afterwards.

Control-byte self-scan over both changed files with grep -naP returned no hits, in addition to the repo gate above.

Still draft, still Fixes #5293 in the body, still no tolerant dual-read on the views prop.


Generated by Claude Code


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 24, 2026 13:09
@yinlianghui
yinlianghui added this pull request to the merge queueAug 24, 2026
Merged via the queue into main with commit 53dc89dAug 24, 2026
23 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-5293-viewsort-order-spelling branch August 24, 2026 13:21
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ObjectViewProps.views[].sort declares direction, but every sort consumer reads order — a host-supplied desc view silently sorts ascending

2 participants

@yinlianghui@claude