Skip to content

fix(providers): type the upload adapter's scope from the spec's UploadScope (objectui#12055) - #12428

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-12055-upload-scope-type
Oct 15, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-12055-upload-scope-type

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12055
Clause-②: no (narrowing)

What changes

createObjectStackUploadAdapter's scope option (ObjectStackUploadAdapterOptions.scope in @object-ui/providers) was an open string. It is now API.UploadScope: the spec's upload-scope vocabulary, UploadScope from @objectstack/spec/api, reached through the API namespace that @object-ui/types already re-exports (export type * as API from '@objectstack/spec/api'). This is the type half triage's answer C left on the card; the shared half (the path fallback removed) landed as PR #12058.

  • No hand copy, no new dependency, no new export. @object-ui/providers already depends on @object-ui/types, and @object-ui/types depends on @objectstack/spec, so package.json and the lockfile do not change. The emitted UploadProvider.d.ts gains one type-only line, import type { API } from '@object-ui/types', and the emitted JS is unchanged (the import is erased: 0 hits in dist/UploadProvider.js). Named here for the contract review, as the dispatch asked.
  • Docblock. It names the values by reference to the spec type, says a value outside it does not compile and is refused by the server with 400, and says an omitted scope sends none, so the server applies the default the spec's upload request declares. It no longer points at the sys_file select in @objectstack/service-storage as the authority.
  • Callers. The only in-repo caller that passes a scope is RecordAttachmentsPanel (scope: 'attachments'), which is in the vocabulary and still compiles. The console's app-wide adapter passes none. Neither source file changes.

Measured before editing (installed @objectstack/spec 18.0.0-next.1)

  • UploadScopeSchema and type UploadScope = z.input of UploadScopeSchema are exported from the ./api subpath; the package root does not export them. Members: tenant, user, private, temp, attachments (public is not one). The card body's list still names public; the type follows the spec, so it does not apply.
  • GetPresignedUrlRequestSchema.scope is UploadScopeSchema.default("user") in the installed JS.

Pins (packages/providers/src/__tests__/objectstack-upload-scope-12055.test.ts)

  • Compile-time, checked by tsconfig.test.json (chained after the source program in type-check):
    • the option type, without undefined, is exactly API.UploadScope, and API.UploadScope is not any;
    • an open string is not assignable to it;
    • @ts-expect-error on { scope: 'avatars' } typed as ObjectStackUploadAdapterOptions.
  • Runtime: the existing pins stay as they were: scope: 'attachments' is forwarded unchanged, an adapter built without a scope sends none (with or without a path).

Evidence (head 7d5d8f2dd, every run after the last commit)

  • pnpm --filter @object-ui/providers type-check (echoes tsc --noEmit && tsc -p tsconfig.test.json): VERDICT command-exit 0. tsc -p tsconfig.test.json --listFiles lists the test file once, and lists the spec's dist/api/index.d.mts.
  • pnpm exec vitest run packages/providers/ plus the two adapter-factory suites (RecordAttachmentsPanel.affordanceGrant-12047, App.uploadAltitude-10131): Test Files 5 passed (5), Tests 23 passed (23); the 12055 file runs 6 tests, all passed.
  • pnpm --filter @object-ui/app-shell type-check, after building its 29-package dependency closure at this branch: VERDICT command-exit 0.
  • Ablation (the change committed first; mutation and restore through ablation-replace.mjs with an exit/int/term trap): scope?: API.UploadScope; widened to scope?: string; (anchor 1 to 0, blob changed). tsc -p tsconfig.test.json then fails with exit 2: two TS2344 (the identity pin and the not-an-open-string pin) and TS2578 (unused @ts-expect-error on 'avatars'). Restored: blob equal to HEAD, git diff HEAD empty.
  • Reverse probe across packages (proves app-shell reads the rebuilt declaration, not a cached one): RecordAttachmentsPanel's scope: 'attachments' changed to 'avatars', then app-shell tsc --noEmit fails with exit 2: TS2322, Type '"avatars"' is not assignable to type '"tenant" | "user" | "private" | "temp" | "attachments" | undefined'. Restored: blob equal to HEAD, git diff HEAD empty.
  • Local gates, each exit captured before any pipe, all 0: check-changeset-presence (1 changeset declared), check-changeset-no-major, check-changeset-fixed, check-changeset-overwrite (0 modified), check-changeset-claims, check-control-bytes, check-new-cross-file-line-citations (0 new), check-test-path-roots, check-vi-mock-specifiers, check-phantom-dependencies; check-governed-queue-guard --test on the 3 paths: NOT GOVERNED. ESLint on the 2 touched files: 0 errors, 7 warnings (react-refresh/only-export-components and react-hooks/refs), none on a line this PR changes. Repo-wide lint and the rest of the farm are CI's.
  • Not run, not owed: check:spec-floors, check:self-import (no package.json changes).

Changeset

.changeset/12055-upload-scope-type.md: @object-ui/providers minor, with the breaking meaning (TypeScript only: a scope outside the vocabulary no longer compiles; the server already refused it) and the remedy, and Clause-②: no (narrowing).

Acceptance notes

  • The pending changeset .changeset/12055-upload-path-not-scope.md (from PR fix(providers): the ObjectStack upload adapter never sends an upload path as the storage scope (objectui#12055) #12058, not yet released) says "The option's type is unchanged (string)." This PR makes that sentence false before it ships. It is left untouched because the claim's file surface names one changeset; the new changeset says it supersedes that note. If the seat prefers one coherent CHANGELOG entry, the remedy is to delete that one sentence.
  • The claim's line is Clause-②: no; this body carries Clause-②: no (narrowing) as the dispatch asked. No objectui gate reads the line.

Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB


Generated by Claude Code

…dScope (objectui#12055)

`ObjectStackUploadAdapterOptions.scope` was an open `string`, so an author
could name a scope the storage service refuses with 400. It is now the
spec's upload-scope vocabulary, `UploadScope` from `@objectstack/spec/api`,
reached through the `API` namespace `@object-ui/types` already re-exports:
no hand copy, no new dependency, no new export.

Pins: the option type equals the spec type and is not an open string; a
`@ts-expect-error` refuses `scope: 'avatars'`; the existing forwarding and
no-scope pins stay as they were.

Claude-Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 69 chunks) 3076.0 KB 3119.4 KB
Main entry chunk (gzip) 73.9 KB 350 KB
Entry file index-BPLAuxho.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 20.90KB 7.67KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 591.88KB 142.76KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 250.77KB 70.23KB
fields (index.js) 282.89KB 72.11KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.26KB 11.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.72KB 48.07KB
plugin-dashboard (index.js) 143.88KB 38.88KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.05KB 69.25KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 179.38KB 46.59KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 261.69KB 72.58KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 123.37KB 31.61KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.99KB 23.23KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

…(objectui#12055)

The pending entry from the shared half said the scope option's type is
unchanged (`string`); the type half narrows it, and both entries publish
in one release. Delete that sentence, and the newer entry's sentence that
superseded it. Claim amendment 1 on objectui#12055 authorises the edit.

Claude-Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 69 chunks) 3076.0 KB 3119.4 KB
Main entry chunk (gzip) 73.9 KB 350 KB
Entry file index-BPLAuxho.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 20.90KB 7.67KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 591.88KB 142.76KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 250.77KB 70.23KB
fields (index.js) 282.89KB 72.11KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.26KB 11.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.72KB 48.07KB
plugin-dashboard (index.js) 143.88KB 38.88KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.05KB 69.25KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 179.38KB 46.59KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 261.69KB 72.58KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 123.37KB 31.61KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.99KB 23.23KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Type Check red on ee9039864: a build-order defect outside this diff · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-15T05:10Z

What fails: Type Check (check-run 116257240226): @object-ui/plugin-list#type-check exited 2. These are the same three diagnostics objectui#12424 recorded on PR #12419, in files this PR does not touch:

  • packages/plugin-grid/src/ObjectGrid.tsx:71, TS2307: cannot find module @object-ui/plugin-detail;
  • :5575 and :5628, TS2345: unknown is not assignable to the conflict-detail type. The type comes from that unresolved module.

Why, measured on main:

  • packages/plugin-list/src/__tests__/ListView.gridRowColorSelect-12393.test.tsx:79 imports ../../../plugin-grid/src/ObjectGrid by relative path. It landed with PR fix(plugin-grid): ObjectGrid projects the row colour's field (objectui#12393) #12408, as 2fc31ea94a. tsconfig.test.json includes it, so plugin-list's type-check compiles ObjectGrid.tsx, which imports @object-ui/plugin-detail and resolves its built dist types.
  • @object-ui/plugin-list declares neither @object-ui/plugin-grid nor @object-ui/plugin-detail. So turbo's type-check dependsOn: ["^build"] never orders plugin-detail#build before it.
  • The race fires when plugin-detail#build is a cache miss in the same run, which is what this PR does. It changes @object-ui/providers, so fields#build and plugin-detail#build re-execute (the run's turbo summary: @object-ui/fields#build … MISS, @object-ui/plugin-detail#build … MISS). On main, and on PRs that leave that cache warm, the dist is replayed first and the check is green.

Why it is not this PR's code: the diff is UploadProvider.tsx's scope type, one test beside it and two changesets. The failing program is plugin-list's test program. No fix exists yet.

Proposed patch, carried on objectui#12424: declare "@object-ui/plugin-grid": "workspace:*" in packages/plugin-list/package.json devDependencies, and regenerate the lockfile. Then ^build orders plugin-grid#build, and with it plugin-detail#build, before plugin-list's type-check. Neither plugin-grid nor plugin-detail depends on plugin-list, so there is no cycle. The alternative is to drop the cross-package relative import from the test.

Next: the one failed-job re-run on this head. A second failure makes this the blocker, and the fix lands first.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ee90398643e558c743efe688b225f1b29bd38537
Local-runs: none

Read, read-only: card #12055 (body and every comment, rulings and earlier records included), PR #12428 (body, file list, net diff against main at the merge-base 7c13d30527), the check-runs on the head, the committed trees at the head and at the merge-base, and the published type text of @objectstack/spec@18.0.0-next.1 (the version the lockfile resolves), read from the registry tarball. Nothing built, run or re-run.

① Derived judgments

The file list is four paths: packages/providers/src/UploadProvider.tsx, packages/providers/src/__tests__/objectstack-upload-scope-12055.test.ts, .changeset/12055-upload-scope-type.md (added) and .changeset/12055-upload-path-not-scope.md (one sentence removed). No governed path and no published schema among them.

  • D1 — the accept set of ObjectStackUploadAdapterOptions.scope (a type @object-ui/providers exports from its root index.ts) narrows from string | undefined to API.UploadScope | undefined. RIGHT. In the published @objectstack/spec@18.0.0-next.1, dist/api/index.d.mts declares UploadScopeSchema as a z.ZodEnum of tenant, user, private, temp, attachments, and type UploadScope = z.input of it; both names are in the ./api subpath's export list and the package root exports neither (0 hits). public is not a member, as triage's answer C and the unlock scan said; the card body's older list naming public does not apply.
  • D2 — the route to the type: import type { API } from '@object-ui/types', which already carries export type * as API from '@objectstack/spec/api' and declares @objectstack/spec ^18.0.0-next.1. No new export, no new dependency (packages/providers/package.json lists only @object-ui/types), no lockfile change. RIGHT, and it honours the standing ban on a new re-export from @object-ui/types. The emitted declaration gains one type-only import of a package @object-ui/providers already depends on; a type import is erased from the emitted JS by construction, and Bundle Analysis on this head reports providers (UploadProvider.js) at 12.07KB / 3.68KB, the figures the earlier dev report read on PR fix(providers): the ObjectStack upload adapter never sends an upload path as the storage scope (objectui#12055) #12058's head.
  • D3 — runtime: no behaviour change. The diff touches a type annotation and a docblock; the presign body stays scope: opts.scope, and the existing runtime pins (a typed scope forwarded unchanged; none sent without a scope, with or without a path) are untouched. RIGHT.
  • D4 — the docblock names the vocabulary by reference to the spec type, says an off-vocabulary value does not compile and the server refuses it with 400, and says an omitted scope sends none so the server applies the default the spec's upload request declares (the published text has scope: z.ZodDefault of that enum). It no longer names the sys_file select in @objectstack/service-storage as the authority. RIGHT; no default value is hard-coded, so the prose cannot go stale against the spec.
  • D5 — callers: RecordAttachmentsPanel passes scope: 'attachments', a member of the union; the console's app-wide adapter passes none. Neither file changes and neither needs to. RIGHT.
  • D6 — the compile-time pins: identity with API.UploadScope, not any, not an open string, and @ts-expect-error on { scope: 'avatars' }. RIGHT and not vacuous: every member of ObjectStackUploadAdapterOptions is optional (baseUrl?, basePath?, scope?, fetchImpl?, credentials?), so the only error that can satisfy the directive is the scope error, which is why the widening ablation surfaces TS2578. They are compiled by packages/providers/tsconfig.test.json (paths: {}, test files included), which the package's type-check script chains after the source program.
  • D7 — the older pending changeset loses the sentence "The option's type is unchanged (string)." and nothing else; frontmatter and every other line are byte-identical in the diff. Its own clause-② sentence still says "no type changes", which describes that entry's diff (PR fix(providers): the ObjectStack upload adapter never sends an upload path as the storage scope (objectui#12055) #12058) and stays true of it. RIGHT.
  • Docs: no docs page documents the adapter's options (content/docs/fields/file.mdx names the factory, not scope; packages/providers/README.md has no scope), so the docblock is the documentation and the earlier dev report's "none" stands.

② Semver level

  • .changeset/12055-upload-scope-type.md: @object-ui/providers minor, BREAKING stated (TypeScript only: a scope outside the vocabulary no longer compiles; the server already refused it), remedy stated (pass a vocabulary value, or omit scope). That is this repo's rule for a breaking change: minor, never major. RIGHT.
  • The Clause-② line reads no (narrowing) on the PR body's second line and in bold in the changeset: no, with the one arm of the closed pair a narrowing takes. Nothing is widened and no yes is owed. The claim's bare no and the body's no (narrowing) agree, and the amendment keeps no. RIGHT.
  • The changeset checks on the head all succeeded: Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report. The one modified pending entry is the amendment's own.

③ Boundary flags

Dev flags (report 6184802562), each answered:

  • The Clause-② arm on the PR body differs from the claim's bare line: answered in ②, well-formed and consistent with the changeset; no objectui gate reads the line.
  • Attribution: the three commits on the branch end with Claude-Session: and Co-authored-by: Claude and name no model; the PR body ends with the session-URL footer. Verified on the three commit messages.
  • No package.json or lockfile change although the surface allowed one: right, see D2.

The out-of-scope finding (the pending-changeset sentence) was taken up by claim amendment 1 (6184832958) and landed in the amendment round (report 6184856123) as the head's last commit; verified in the diff.

open_questions is empty in both reports of this claim. The voided earlier claim's one open question (how the option is typed) was ruled by triage (6081575358, answer C); this head is that answer.

File surface: every changed path is on the claim's surface or the amendment's rider; RecordAttachmentsPanel, packages/providers/package.json, pnpm-lock.yaml and @object-ui/types are untouched, as the surface's conditions required. PR body line one names #12055 with the closing keyword: this is the card's remaining half, so that is the right keyword here.

Gate verdicts on this head

  • 33 check-runs succeeded: every Test shard, Test (dist pins), Lint, Repo Gates, Spec Main Shape Gate, Build & E2E, Build Docs, Bundle Analysis, Governed Surface Queue Guard, Line Citation Gate, the five changeset checks, label, Live E2E (informational). Three skipped by design: Test (coverage), Test (coverage shard), dependabot.
  • ONE red: Type Check (check-run 116257240226), failed step Run type-check, turbo naming packages/plugin-list type-check exit 2. First error line: TS7016 "Could not find a declaration file for module '@object-ui/plugin-detail'" at the @object-ui/plugin-detail import of packages/plugin-grid/src/ObjectGrid.tsx, then two TS2345 cascades at the calls taking { currentVersion?, currentRecord? }. Read on the committed trees: packages/plugin-list/src/__tests__/ListView.gridRowColorSelect-12393.test.tsx imports ../../../plugin-grid/src/ObjectGrid across packages, and plugin-list does not declare @object-ui/plugin-detail, so its type-check compiles ObjectGrid without that dist being built first. None of those three files is in this PR's file list, plugin-detail does not depend on @object-ui/providers, and the identical first error line stands on the merge-base main (7c13d30527) in that commit's scheduled Spec Main Shape Gate run (check-run 116254139467). It is the open card objectui#12422, filed before this PR opened. ⛔ Not attributable to this diff. ⛔ Not cleared by this record: it is the landing's own check-② reading, and until a Type Check run on this head gets past that race, the head's check-runs do not confirm packages/providers' own type-check (the compile-time pins of D6) or app-shell's compile; the readings above rest on the published type text and the diff. Escalated to the seat: re-run Type Check or wait for objectui#12422; do not queue on this run.

Implemented-by: claude/issue-12055-upload-scope-type
Reviewed-by: session_01JZnppgHRp4sREcouhkQYDB

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Seat ACCEPT: objectui PR #12428 at ee9039864 · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-15T05:28Z

Verdict: ACCEPT. Reviewed on GitHub against the claim 6184490685 and its amendment 6184832958 on objectui#12055, and against the dev's reports. The PR lands in this act.

  • Shape:
    • Draft, base main, assignee sunhaolin.
    • Line 1 is Fixes #12055, the body's only closing keyword. Line 2 is Clause-②: no (narrowing).
    • 4 files. The path face is NOT governed, and there is no published schema.
  • The fix, read in the diff:
    • ObjectStackUploadAdapterOptions.scope is API.UploadScope: tenant | user | private | temp | attachments, the spec's own type, reached through @object-ui/types' existing API namespace.
    • There is no hand copy, no new dependency and no new export. The runtime is unchanged.
    • The compile-time pins are not vacuous: every option member is optional, so only the scope error can satisfy the @ts-expect-error. Widening the type back to string turned all three red.
  • The narrowing's review: the contract-review-tier record 6185031189 reads PASS on this head. I checked its lines:
    • Served-tier: CONTRACT_REVIEW_TIER;
    • Head-sha equal to the head;
    • Local-runs: none;
    • the signed Implemented-by / Reviewed-by pair;
    • no model name.
  • The rider (amendment 1): two sentences of this card's pending-changeset prose are removed. The frontmatter and every other line are byte-identical, so the release notes no longer say the option stays string.
  • Changeset: @object-ui/providers minor, with the BREAKING meaning and its remedy, per objectui AGENTS.md §9. ⛔ Not major.
  • CI on this head: 37 check-runs, read off the latest per name: 34 success and 3 expected skips.
  • Out of scope: none left open. The pending-changeset sentence rode this PR as amendment 1.

Landing: ready and auto-merge through the queue, in this act.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 15, 2026 05:29
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 15, 2026 05:30
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 24804dc Oct 15, 2026
61 of 62 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12055-upload-scope-type branch October 15, 2026 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants