Skip to content

fix(designer): retire the formula-expression control instead of renaming its key - #6312

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-6043-designer-formula-key
Aug 25, 2026
Merged

fix(designer): retire the formula-expression control instead of renaming its key#6312
os-support-ai merged 2 commits into
mainfrom
claude/issue-6043-designer-formula-key

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#6043

The Field Designer's formula textarea wrote formula, a key FieldSchema refuses by name, so PUT /api/v1/meta/object/:name returned a hard 422 INVALID_METADATA — and because the key was then stored, it blocked every later save of that object, not just the one that introduced it.

Surfaced by the key-level parity gate built for #5761. Verified on origin/main @ 7ccb53a (⚠️main moved from the ba306e3 the card was triaged on; every premise was re-derived). All measurements are against the installed @objectstack/spec17.2.0.

The premise holds

FieldSchema.safeParse({ type:'formula', label:'Tax', formula:'price * quantity' })
=> success = false
=> unrecognized_keys ['formula']
"Did you mean `formula` -> `expression`?"

Why the obvious rename was refused — the measurement that decides this card

The spec ships a rename hint, and taking it would have been a two-line change. It is wrong, and this is the evidence:

FieldSchema.safeParse({ type:'formula', expression: <value> })
'record.price * record.quantity' -> ACCEPTED
'price * quantity' -> ACCEPTED
'!!!not cel at all!!!' -> ACCEPTED <-- no CEL parsing at the key level
'' -> refused (invalid_union)

FieldSchema judges the key name, never the expression language. Only the empty string is refused, so a rename buys a green parse for arbitrary garbage.

That matters here specifically because spec expression is CEL rooted at record (record.amount * 0.1), while this control's own placeholder taught e.g. price * quantity — bare field refs. This repo has already measured what those do; celAuthoring.ts states it about the exact scope formulas bind:

'record' — the record is bound ONLY as the record namespace (… formulas). A bare field ref silently evaluates to null at runtime, so the engine flags it as an ERROR with the record.<field> fix.

So a bare rename converts a loud, immediate 422 into a formula that saves clean and then quietly computes nothing — strictly worse than the bug.

Why the control was removed rather than taught CEL

Making refusals loud inside the control needs CEL lint, autocomplete and returnType inference. That is CelPredicateField, and it is not reachable from here:

  • @object-ui/app-shelldepends on@object-ui/plugin-designer (declared in its package.json), so importing the editor back is a dependency cycle.
  • @object-ui/plugin-designer does not depend on @objectstack/formula at all — it has no CEL engine.

Building a second formula-authoring surface inside plugin-designer is a feature, not this fix. The control is removed instead, and the capability is not lost: metadata-admin's ObjectFieldInspector authors expression through CelPredicateField with live lint and stamps returnType from the inferred CEL type, labelled Formula (CEL). Its own comment records that it "replaces the formula textarea that previously edited a formula key the runtime never read" — this repo has retired a formula textarea once already, for this reason.

Nothing that worked is being taken away. Every save carrying formula returned 422, so no author can have been successfully using this control — it has only ever failed.

returnType: omitted, deliberately. It is derivable only by inferring the CEL result type, which needs the engine this package does not have; and with no expression control there is nothing to infer from. The surface that can infer it already stamps it.

The field TYPE formula is kept. Measured: FieldSchema.safeParse({ type:'formula', label:'Tax' }) succeeds — it is a valid spec FieldType. Only the expression key was ever refused, so removing the type would have broken formula fields outright. Authors still declare a field computed; they author its expression where it gets checked.

What changed

FileChange
types/src/designer.tsDesignerFieldDefinition.formula removed + tombstone
plugin-designer/src/FieldDesigner.tsxtextarea control, both write paths (create/update), edit seed
plugin-designer/src/MetadataFieldsPage.tsxServerFieldSchema key, both converters, formula added to RETIRED_FIELD_KEYS
app-shell/src/services/MetadataService.tsFieldMetadataPayload key + toFieldPayload
app-shell/…/previews/object-fields-bridge.tsread + write removed (see below)
scripts/check-designer-field-key-parity.mjsledger entry removed (ratchets both ways)

The tombstone is half the fix. With the control gone, an author has no way left to clear a stored formula, so without RETIRED_FIELD_KEYS an already-blocked object would stay blocked forever — carryOver spreads the previous server def verbatim. It is dropped, not migrated to expression, for the same reason the rename was refused: laundering a non-CEL string into a valid key name is the silent failure this card exists to prevent. A stored expression is not stripped — it is a real FieldSchema key and rides through untouched.

A third emit site, named by neither the card nor the gate.object-fields-bridge.ts also read and wrote formula; FrameworkFieldDef is not one of the parity gate's PAYLOAD_SHAPES, so the gate was green over it by construction. It is in this PR by necessity (it consumes DesignerFieldDefinition). ⚠️Correction to my claim comment: I called it a live third write site — measured, it is dead code, zero importers repo-wide, so this edit is behaviourally inert. Filed as #6309, together with a lossy round-trip in its serializeDesignerField that contradicts its own header.

Verification

All commands from the repo root per AGENTS.md; pnpm exec vitest run <paths>, never --filter or cd packages/x.

Tests — green at 9798788b7, the final commit (22 files / 178 tests, the affected-set regression run; the 3 new files contribute 21):

packages/plugin-designer/ packages/types/src/__tests__/designer-field-types.test.ts
packages/app-shell/src/services/ …/previews/object-fields-io.spec-keys.test.ts
packages/fields/src/__tests__/richtext-cell-renderer-5452.test.tsx
scripts/__tests__/check-designer-field-key-parity.test.ts
=> Test Files 22 passed (22) · Tests 178 passed (178)

Assertions are on the bytes actually PUT (JSON.parse of the captured request body through a real MetadataClient/ObjectStackAdapter over a fetch double), not on the argument handed to the client — a property whose value is undefined is a key zod's strict object COUNTS but JSON.stringify DROPS.

Ablation — each repair point reverted alone, mutation proven on disk in both directions, restored under trap … EXIT INT TERM with absolute paths, git diff HEAD empty after each leg. No rebuild leg is needed and that is measured, not assumed: the root vitest config aliases every @object-ui/* to packages/*/src, so these tests import the mutated source directly — no dist/ in the path.

LegRevertedPredictedObserved
A1'formula' out of RETIRED_FIELD_KEYS2 red✅ 2 — strips the refused key… + every field it PUTs parses…
A2formula: designed.formula back into fromDesignerField1 red✅ 1 — drops a formula smuggled onto a designer field
A3formula: field.formula back into toFieldPayload1 red✅ 1 — drops a formula smuggled onto the field
A4textarea control back into the drawer schema2 red✅ 2 — no formula field in the create drawer + …edit drawer

⚠️A2/A3 were reported VOID on the first attempt and are re-run here. The mutation had landed both times; the probe was broken — grep -cF with a multi-line pattern does not search for that block, -F treats each line as a separate alternative, so " };\n}" matched every closing brace and the "removed text" count came back 59 instead of 0. The guard refusing to read a test result from an unverified mutation is the behaviour working. The underlying error was mis-classification: A2/A3 are pure insertions like A4, so a "removed text" direction cannot exist for them; their honest proof is before-count 0 / after-count 1 on a single-line marker.

Trap species addressed by name: a degenerate control was caught live — the grid mock fills rows from a promise, so the first draft queried row buttons before mount. Had that file only asserted absences, the empty tree would have made every one of them pass. Every absence in the control test is now paired with a positive control (drawer-field-referenceTo, the sibling control in the same section through the same testid channel). Ghost assertions are labelled where they exist: the expression/returnType round-trip row and the lookup round-trip row also pass on a revert and say so in comments — they are must-not-change pins, not two-world assertions.

Gates — derived by enumerating each CI job's own step list, not from memory. Run locally, each reading its own verdict line (exit codes captured before any pipe):

check:designer-field-key-parity ✅ (ledger entry gone, gate still OK) · check:i18n-keys ✅ · check:control-bytes ✅ · check:vi-mock-specifiers ✅ · check:spec-symbols ✅ · check:self-import ✅ · check:phantom-deps ✅ · check-changeset-presence ✅ · check-changeset-no-major ✅ · check-changeset-fixed ✅ · type-check (types + plugin-designer + app-shell) ✅

Type-check genuinely covers the new tests — each package's type-check runs tsc -p tsconfig.test.json, and --listFiles confirms all three new files are in the set (not excluded).

Lint, declared narrowing.pnpm lint here is turbo run lint (per-package eslint .), so linting the three packages I touched is the complete lint for every package I touched — run with --force to defeat turbo cache: 4 tasks successful, 0 errors (2678 warnings = the repo's pre-existing baseline; check-lint-coverage.mjs reports 46/46 packages, 0 outstanding errors). Per-file --format json over my 8 changed files: 0 errors, 13 warnings, all 13 on lines I did not touch. Invariance justifying the narrowing: eslint.config.js sets no parserOptions.project / projectService, so linting is not type-aware and this diff cannot move the verdict on any untouched file.

Changeset:minor on all three packages, stating in words that this is a behaviour change on an authoring surface (a control is removed). Never major, per the version-alignment rule.

Known leftover, declared

appDesigner.fieldDesigner.formula is now a dead key in ten locale packs plus the designer defaults map. Left in place deliberately: check:i18n-dead-keys is report-only and wired into no workflow, and removing it is an 11-file translation-hygiene diff coupled to the defaults-map mirror gate. Filed as #6310 rather than folded in here.

Out-of-scope findings filed

⛔ Left as draft: the PM lands it.


Generated by Claude Code

…ing its key
The Field Designer's formula textarea wrote `formula`, a key `FieldSchema`
refuses BY NAME, so `PUT /api/v1/meta/object/:name` returned a hard 422
`INVALID_METADATA` that blocked every later save of the object.
The spec spells the concept `expression`, and the rename was deliberately NOT
taken. `FieldSchema` judges the key and never the expression LANGUAGE: measured
on @objectstack/spec 17.2.0 it accepts `expression: 'price * quantity'` and even
`expression: '!!!not cel at all!!!'`. Spec `expression` is CEL rooted at
`record`, while this control's own placeholder taught `price * quantity` — bare
field refs that evaluate to null silently under the scope formulas bind. A
rename would have converted a loud 422 into a formula that saves clean and
computes nothing.
Making refusals loud in the control needs CEL lint and returnType inference,
i.e. CelPredicateField — which lives in @object-ui/app-shell, and app-shell
depends on @object-ui/plugin-designer, so it cannot be imported back without a
cycle. Expressions are authored in metadata-admin's ObjectFieldInspector, which
lints against the real @objectstack/formula engine. The field TYPE `formula`
stays: it is a valid spec FieldType and only the expression key was refused.
`formula` joins RETIRED_FIELD_KEYS so an object already carrying it is stripped
clean on its next save rather than staying blocked forever — with the control
gone there is no other way left to clear it. A stored `expression` is untouched.
Also drops the key from object-fields-bridge.ts, a third emit site the parity
gate does not cover, and clears the ledger entry, which ratchets both ways.
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)3222.9 KB3266.6 KB
Main entry chunk (gzip)154.1 KB350 KB
Entry fileindex-B0nT1urh.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.40KB59.89KB
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.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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3222.9 KB3266.6 KB
Main entry chunk (gzip)154.1 KB350 KB
Entry fileindex-B0nT1urh.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.40KB59.89KB
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.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

@os-support-ai
os-support-ai marked this pull request as ready for review August 25, 2026 12:39
@os-support-ai
os-support-ai added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit 864154eAug 25, 2026
28 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-6043-designer-formula-key branch August 25, 2026 12:55
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-support-ai@claude