Skip to content

fix(fields,i18n): localize manage_sharing and pin the curated capability set to PLATFORM_CAPABILITIES - #6323

Merged
os-support-ai merged 4 commits into
mainfrom
claude/issue-6285-capability-labels-derive-from-spec
Aug 25, 2026
Merged

fix(fields,i18n): localize manage_sharing and pin the curated capability set to PLATFORM_CAPABILITIES#6323
os-support-ai merged 4 commits into
mainfrom
claude/issue-6285-capability-labels-derive-from-spec

Conversation

@os-support-ai

@os-support-aios-support-ai commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6285

Note

Shape adjudicated on #6285 after both candidates were measured. The first commit implemented a runtime derivation and hit a one-way coverage ratchet; this one keeps a repo-local literal and makes its Mirrors claim mechanical with a spec-importing parity test. No guard was moved. Draft on purpose — the PM lands it. The A-vs-B table below is kept deliberately: it is the record of why B was chosen and why the ratchet was not touched.

The defect (confirmed, re-measured, not inherited)

CURATED_CAPABILITY_LABELS in packages/fields/src/widgets/CapabilityMultiSelectField.tsx was a seven-member literal under a doc comment claiming it mirrored @objectstack/spec/security's PLATFORM_CAPABILITIES. Read out of the installed @objectstack/spec@17.2.0 on this branch's base:

PLATFORM_CAPABILITIES (8): manage_users manage_org_users manage_metadata
manage_platform_settings setup.access setup.write
studio.access manage_sharing
local Set (7): the same, minus manage_sharing

So manage_sharing fell through to byName.get(name)?.label — the English label the sys_capability registry serves — and rendered untranslated in all ten packs, beside seven siblings that localize. A user-visible missing translation.

Nothing caught it, and the reason is exact: scripts/check-i18n-call-site-keys.mjs reads that declaration as the capability.label. family's vocabulary and checks the members it names have en keys. All seven did. No instrument compared the vocabulary to the array it was named after, so the member the list never mentioned was invisible to the whole toolchain.

A finding the card did not carry, and it changes the fix:capability.label.manage_sharingdid not exist as an i18n key anywhere — not in the ten packs, not in useFieldTranslation.ts's provider-less defaults map. Fixing membership alone would have traded a missing translation for a raw i18n key on screen, which is worse than the defect.

What is in this diff

File(s)Change
CapabilityMultiSelectField.tsxmanage_sharing joins the curated set; the doc comment stops asserting the mirror and names the test that checks it; labelFor gains defaultValue
useFieldTranslation.ts + 10 packages/i18n/src/locales/*.tscapability.label.manage_sharing authored (Manage Sharing / 管理共享 / 共有の管理 / 공유 관리 / Freigaben verwalten / Gérer le partage / Gestionar el uso compartido / Gerenciar compartilhamento / Управление общим доступом / إدارة المشاركة)
CapabilityMultiSelectField.specParity-6285.test.tsxnew; 7 assertions — set equality with the spec in both directions, plus the rendering half

scripts/check-i18n-call-site-keys.mjs is untouched in the final diff (byte-identical to the merge base). The family keeps its kind: 'set' vocabulary.

labelFor's defaultValue is deliberate and survives either shape: a capability that lands in a future spec bump before its translation is authored degrades to the registry's English label rather than rendering capability.label.foo_bar at a user. It is a last-resort fallback, not the mechanism — the parity test reds in CI on the same event.

File surface note. The dispatch scoped this to CapabilityMultiSelectField.tsx and its tests. Eleven further files are touched, and each is forced rather than chosen: the ten packs and the defaults map, because the new member has no key without them and all-locales-key-parity.test.ts requires every pack to define every en key. None of the four sibling branches in flight this wave touches any of them — checked with git diff --name-only origin/main...origin/<branch> on all four — and PR #6292's packages/fields/src/index.tsx is untouched here.

Why a literal, when the card asked for a derivation

The derivation was built and measured, not argued about. It is the first commit on this branch.

readVocabulary parses repo source and needs a literal new Set([…]). With the derivation in place and the registry entry left alone, the gate says so itself:

packages/fields/.../CapabilityMultiSelectField.tsx:193:12 [unreadable-vocabulary] capability.label.
set CURATED_CAPABILITY_LABELS in packages/fields/src/widgets/CapabilityMultiSelectField.tsx
CHECK_EXIT=1

So the family would have to move to enumerable: false, and scripts/__tests__/check-i18n-call-site-keys.test.ts pins the split as a one-way ratchet"paying off a unnamed-union or external-vocabulary entry raises coverage without failing this test — but LOSING coverage does fail it."

 families with a vocabulary members checked exactly ratchet test
base @ 7ccb53a92 18 112 green
A runtime derivation 17 105 RED (expected 17 >= 18)
B literal + parity test (this) 18 113 green

Both rows measured, not reasoned. B is one member ahead of base — the extra member is manage_sharing.

Two other routes were checked and closed: the gate's own documented bridge for an external vocabulary ("a repo-local exhaustive Record<Union, …> this reader can read") is unavailable, because PlatformCapability.name is typed string and the spec publishes no union to key a Record by; and pointing the reader at the dependency's own source is out, because @objectstack/spec ships only the *.zod.ts subset under src/ and PLATFORM_CAPABILITIES is not in it.

Bundle size is not the reason, and that is worth stating because the neighbouring precedent (useTenancyPosture.ts) is about bundle size. Measured here on the real console build: the derivation cost +0.3 KB gzipped on the eager closure. It was affordable. It simply cost a guard.

And the benefit the derivation promised is not available in either shape. "The next spec addition arrives automatically" cannot happen: a new capability still needs capability.label.* authored by a human in ten packs, or it renders registry English (this card's exact defect) or a raw key. manage_sharing is the proof — it had no key. Derivation does not remove the human step; it only chooses which instrument reports it. B keeps two instruments reporting it — the static gate and the test — for the same user-visible outcome.

Verification — all at 823a024cc, worktree clean

CheckResult
pnpm check:i18n-keysexit 0 — "25 declared — 18 with a static vocabulary (113 member key(s) checked exactly), 7 with no enumerable member set"
pnpm exec vitest run scripts/__tests__/check-i18n-call-site-keys.test.ts109 passed — the ratchet is green, unmoved
pnpm check:i18n-driftexit 0 — "0 en value(s) changed (1 key(s) added, 0 removed)"
pnpm check:spec-symbolsexit 0 — unbacked-claim count unchanged at 18 (the declaration stays module-local, so no CLAIM_ALLOW entry is added or needed)
node scripts/check-changeset-presence.mjsexit 0 — 13 source files, 1 changeset
pnpm turbo run type-check (fields, i18n) + pnpm type-check:scriptsexit 0
pnpm exec vitest run packages/fields/112 files, 1846 passed
pnpm exec vitest run packages/i18n/55 files, 910 passed
eslint --no-inline-config on all 13 changed .ts/.tsx filesexit 0, 0 errors, 9 warnings — 7 pre-existing in the widget, 2 in the new test mirroring the sibling test file's own as any idiom
node scripts/check-eager-closure-budget.mjsexit 0 (measured on the derivation commit, the only change that could move it): 3222.9 → 3223.2 KB against a 3266.6 KB ceiling

type-check for @object-ui/fields runs tsc --noEmit && tsc -p tsconfig.test.json, and --listFiles confirms the new test is inside that program (1 hit) — so "type-check clean" is a statement about it, not around it. The test reaches readVocabulary through a relative import of scripts/check-i18n-call-site-keys.mjs, the same arrangement packages/layout/src/__tests__/readme-registration-keys.test.ts uses for scripts/component-registrations.mjs, and roots it at the process cwd rather than resolve(__dirname, …) because this package's test program deliberately does not name types: ['node'] — a test file is not the place to change that program.

Ablation — two legs, both directions

Committed first. Mutation proven on disk each time by two separate greps (injected and removed text) and a blob-hash move; restored under trap restore EXIT INT TERM calling git checkout HEAD -- "$REPO_ROOT/<path>" (absolute, HEAD-pinned so a written index cannot hand the mutation back); after each leg git diff HEAD --stat was empty and the blob hash was back at cf60991d….

No rebuild leg is needed and that is a property of the harness, not an omission: the test imports the subject by relative path and @object-ui/i18n resolves through the root vitest alias to packages/i18n/src, so nothing here reads dist/.

Leg 1 — a spec member missing from the literal (the defect this card is). Predicted 3 of 7 red and named which; observed exactly those:

× declares exactly the spec's capability names, in both directions
× renders `manage_sharing` as its localized label, not the registry English
× renders every declared platform capability as its localized label
Tests 3 failed | 4 passed (7)

Leg 2 — a stale member the spec never had (ghost_capability). Predicted exactly 1 red, and it is the assertion this shape adds over a rendering-only pin — a stale member is invisible to every render, because nothing ever asks for it:

× declares exactly the spec's capability names, in both directions
Tests 1 failed | 6 passed (7)

The assertions that stayed green in each leg are the ones describing behaviour the mutation did not touch, which is the point: the file is not one assertion wearing seven hats.

The most instructive thing here is a prediction that was wrong

Before touching the console, the eager-closure gate was predicted RED, from a standalone esbuild probe: spec root alone 398,100 B gzipped, root + @objectstack/spec/security 455,547 B — +57,447 B against 43.7 KB of aggregate headroom and 18.1 KB on vendor-objectstack. useTenancyPosture.ts records +237 KB minified for the same import and agrees in spirit. Every number was real.

The real console before/after build measured +0.3 KB, green — off by two orders of magnitude. The probe answered marginal cost over the spec root alone; the question was marginal cost over the console's actual graph, which already reaches those modules. A wrong instrument reading as a confident number, and it nearly produced a false escalation on a cost that does not exist. The only thing that caught it was building the real artefact and reading the real gate instead of trusting the probe. Worth more to the next reader than the fix itself.

A second miss belongs next to it: check:i18n-keys going green after the family conversion was predicted and observed, and the prediction stopped there — that a gate's own __tests__ can pin invariants the gate's exit code cannot was not anticipated, and it is the finding that decided the shape.


Generated by Claude Code

…ILITIES
`CURATED_CAPABILITY_LABELS` was a seven-member literal under a doc comment
claiming it mirrored `@objectstack/spec/security`'s `PLATFORM_CAPABILITIES`.
The spec grew an eighth member and the copy did not follow, so `manage_sharing`
fell through to the English label the `sys_capability` registry serves and
rendered untranslated in all ten packs beside seven siblings that localize.
The set now derives from `PLATFORM_CAPABILITIES`, applying the same dot ->
underscore transform the call site uses, and `capability.label.manage_sharing`
is authored in the ten packs and in the field widgets' provider-less defaults
map. `labelFor` gains a `defaultValue` so the window between a spec bump and a
translation degrades to the registry label instead of a raw i18n key.
KNOWN RED, deliberately not worked around: deriving turns the declaration into a
computed value, which `scripts/check-i18n-call-site-keys.mjs`'s `readVocabulary`
cannot read, so the `capability.label.` family moves to `enumerable: false` /
`external-vocabulary`. That drops `counters.enumerableFamilies` 18 -> 17 and
`counters.checkedMembers` 112 -> 105, and
`scripts/__tests__/check-i18n-call-site-keys.test.ts` pins both as a ONE-WAY
ratchet ("LOSING coverage does fail it"). Re-baselining that ratchet to land this
shape is a maintainer decision, not this branch's to take — see the report on
objectui#6285.
Part of #6285
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3223.2 KB3266.6 KB
Main entry chunk (gzip)154.1 KB350 KB
Entry fileindex-BLk6pVG3.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.96KB4.16KB
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)505.63KB114.68KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.44KB59.90KB
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)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.45KB
plugin-designer (index.js)212.33KB42.81KB
plugin-detail (index.js)245.10KB62.31KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.92KB30.85KB
plugin-gantt (index.js)164.17KB39.89KB
plugin-grid (index.js)201.14KB54.40KB
plugin-kanban (index.js)52.83KB14.55KB
plugin-list (index.js)111.94KB27.24KB
plugin-map (index.js)20.09KB6.62KB
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)9.26KB3.13KB
plugin-view (index.js)84.55KB20.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)54.84KB18.43KB
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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
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

… not by derivation
PM adjudication on #6285 chose shape B over the runtime derivation the first
commit implemented, and this commit is that switch. Nothing about the defect or
its user-visible fix changes: `manage_sharing` still joins the curated set and
still gets its `capability.label.*` key in the ten packs and in the field
widgets' provider-less defaults map, and `labelFor` keeps the `defaultValue`
degradation.
What changes is HOW the `Mirrors PLATFORM_CAPABILITIES` claim is held.
- `CURATED_CAPABILITY_LABELS` goes back to a repo-local literal, now with
`manage_sharing`. That keeps it readable to `check-i18n-call-site-keys.mjs`,
whose `readVocabulary` needs a literal `new Set([…])`; the derivation made it
`unreadable-vocabulary` and forced the family to `enumerable: false`, dropping
the gate from 18 vocabularies / 113 exactly-checked members to 17 / 105 and
tripping the one-way coverage ratchet in
`scripts/__tests__/check-i18n-call-site-keys.test.ts`. Moving that ratchet is
gate-weakening and belongs on the maintainer's floor, so it was not moved.
- `scripts/check-i18n-call-site-keys.mjs` is reverted to the base version; the
family keeps its `kind: 'set'` vocabulary.
- The pin is renamed `specDerivation` -> `specParity` and grows the assertion
that makes the claim mechanical: it reads the declaration through the gate's
OWN `readVocabulary` and asserts set equality with `PLATFORM_CAPABILITIES`
(dot -> underscore normalised) in BOTH directions, alongside the rendering
assertions it already carried.
Measured under this shape: `check:i18n-keys` green at 18 vocabularies / 113
members — one MORE than base's 112, the extra member being `manage_sharing` —
and the ratchet test 109/109 green. The derivation remains a coherent choice and
the branch history plus the PR body keep its measurements; it simply costs a
guard, and this shape costs none.
Fixes#6285
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
@os-support-aios-support-ai changed the title fix(fields,i18n): derive the capability label set from PLATFORM_CAPABILITIES — shape decision needed, one gate ratchet redfix(fields,i18n): localize manage_sharing and pin the curated capability set to PLATFORM_CAPABILITIESAug 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3223.2 KB3266.6 KB
Main entry chunk (gzip)154.2 KB350 KB
Entry fileindex-UQJkfLNc.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.96KB4.16KB
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)505.75KB114.70KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.89KB60.02KB
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)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.45KB
plugin-designer (index.js)211.95KB42.75KB
plugin-detail (index.js)245.10KB62.31KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.92KB30.85KB
plugin-gantt (index.js)164.14KB39.87KB
plugin-grid (index.js)201.14KB54.40KB
plugin-kanban (index.js)52.83KB14.55KB
plugin-list (index.js)111.94KB27.24KB
plugin-map (index.js)20.09KB6.62KB
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)9.26KB3.13KB
plugin-view (index.js)84.55KB20.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)54.84KB18.43KB
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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3223.2 KB3266.6 KB
Main entry chunk (gzip)154.2 KB350 KB
Entry fileindex-UQJkfLNc.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.96KB4.16KB
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)505.75KB114.70KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.89KB60.02KB
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)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.45KB
plugin-designer (index.js)211.95KB42.75KB
plugin-detail (index.js)245.10KB62.31KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.92KB30.85KB
plugin-gantt (index.js)164.14KB39.87KB
plugin-grid (index.js)201.14KB54.40KB
plugin-kanban (index.js)52.83KB14.55KB
plugin-list (index.js)111.94KB27.24KB
plugin-map (index.js)20.09KB6.62KB
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)9.26KB3.13KB
plugin-view (index.js)84.55KB20.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)54.84KB18.43KB
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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
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

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.

CURATED_CAPABILITY_LABELS has drifted from PLATFORM_CAPABILITIES — manage_sharing silently loses its localized label

1 participant

@os-support-ai