Skip to content

fix(plugin-form): a create form preselects the option a field marks default: true (objectui#11914) - #11944

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11914-select-default-option
Oct 8, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11914-select-default-option

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11914
Clause-②: no

What changes

A create form preselects the option a field's option list marks default: true, when the field declares no defaultValue. This is the rule the server's insert path applies when a create omits the field. The objectstack tutorial's Create Ticket form now opens with Priority = Low and Status = Open, and submits without a manual pick.

Where. The fix is in packages/plugin-form/src/schemaDefaults.ts, in schemaDefaultValues. That is the one function every object-form container seeds a create form through (ObjectForm directly; ModalForm, DrawerForm, TabbedForm, SplitForm and WizardForm through seedCreateValues). A new module-private optionListDefault reads the option list. No second derivation was added in the select widget.

Measured first, on main f1781be3a (H0)

The new pin was run against the unchanged source. It rendered the console's create dialog (the global ModalForm) on the tutorial's ticket object, verbatim. 11 of 17 tests failed. The main failure: AssertionError: expected 'Select an option' to contain 'Low'. On main, schemaDefaultValues returns {} for that object, so the premise holds on current main. The module docblock said it deliberately ignored the option flag "because the server reads defaultValue alone". That stopped being true when the engine began falling back to the marked option (objectstack#7246).

Bound: H0 rendered the real ModalForm, ObjectForm and field widgets with React Testing Library. It did not drive a booted console in a browser against a live backend.

The rule: the engine's, read client-side (H1, H2, H3)

This is a read-only check of objectstack ObjectQL.applyFieldDefaults / resolveOptionDefault and its test engine-select-option-default.test.ts. The client applies the same rule:

Declared Server stores on omit Create form now opens with
option default: true, no defaultValue the marked option the marked option
static defaultValue + option flag defaultValue defaultValue (unchanged)
runtime defaultValue (NOW(), current_user, CEL) + option flag the resolved token empty, key omitted (unchanged; the flag is NOT seeded in its place)
defaultValue: null + option flag the marked option (== null presence test) the marked option
several marked, single-valued the first the first
marked on a multi-valued field (isMultiValueField: multiselect, or select + multiple) every marked option, as an array every marked option, as an array
multiple: true on a type outside the multi sets a scalar a scalar
option value spelled current_user that literal that literal
marked option with no value nothing nothing

The client asks @objectstack/spec's isMultiValueField for the arity, which is the engine's own predicate. It never reads multiple raw. Only the canonical default key is read: the spec's alias layer normalizes isDefault / selected before metadata is served.

What does not change:

  • A caller seed (initialData / initialValues) and the user's own pick still win.
  • Edit forms are never seeded: they show the stored record.
  • omitServerResolvedDefaults and isRequiredInForm are untouched. An option value is a static literal, so it is submitted like any other seeded value, and a required field the user clears is still refused.

Public surface: unchanged

schemaDefaultValues and seedCreateValues are not on the package entry. They now take a package-local SeedSchemaLike, derived from the published FieldDefaultsSchemaLike plus options / multiple. The published FieldDefaultsSchemaLike keeps exactly its three pinned members (parameterTypesNameable-7324.test.ts passes). No export, prop, type member or packages/i18n key changes. That is why the PR declares Clause-②: no.

Pins and ablation

packages/plugin-form/src/__tests__/optionDefaultSeed-11914.test.tsx, 19 tests:

  • schemaDefaultValues unit cases for every row of the table above, plus the control: options that mark nothing seed nothing.
  • ModalForm (console create dialog), on the tutorial ticket object:
    • Priority and Status are preselected and submitted without a pick;
    • control: a select that marks nothing stays on its placeholder;
    • the user's pick through the control wins;
    • a caller seed wins;
    • a multiselect preselects every marked option (aria-pressed);
    • an edit form over a row that leaves the key absent is not seeded.
  • ObjectForm (page-mode create): preselected on create, not applied on edit.

Ablation, run after the fix was committed: scripts/ablation-replace.mjs (objectstack) replaced const fromOptions = optionListDefault(f); with an undefined assignment.

  • The mutation landed: anchor x1 to x0, blob a8807e5e to bd538283.
  • The pin turned red: 11 failed, 6 passed. These are the same 11 that failed on main.
  • The restore is proven: blob equals HEAD, and git diff HEAD is empty.
  • The tests import source through the root vitest alias, so no dist/ is on the measured path.

Eager closure (Bundle Analysis)

plugin-form is eager, so this was measured under the verify lock. The console vite build ran twice from the same worktree, plus check-eager-closure-budget.mjs. The head build was at 27be779f7. The base build was the same tree with schemaDefaults.ts reverted to f1781be3a; the restore was proven by blob.

eager gzip bytes gate verdict
base (f1781be3a) 3,385,951 green, headroom 0.4 KB
head 3,386,104 green, headroom 0.3 KB
delta +153 gzip (+379 raw)

The growth is in the plugin-form chunk (+154 gzip). Other chunks moved by 1 to 3 bytes from hashed import names. The vendor-objectstack chunk did not move, so isMultiValueField was already in the closure. The change is kept minimal.

Note: main 19a7348 is already a few bytes over the 3307.0 KB ceiling (the seat's main-red card, objectui#11937). This PR's Bundle Analysis is expected red until that card's change lands. It is not addressed here, and scripts/check-eager-closure-budget.mjs is untouched.

Docs

packages/plugin-form/README.md, "What a create form opens with":

  • The table row "an option's default: true: empty" is replaced.
  • So is the paragraph that said only the field-level defaultValue is read.

Both sentences became false with this change. This file is outside the claim's file surface. It was edited because the code change made a published sentence false, and the objectui AGENTS.md docs-driven rule (#2) applies. The report names it as a deviation; it can be dropped from the branch if the seat rules otherwise. No sentence under content/docs/** or skills/** covers select defaults on create forms. A grep for the option flag and for create-form defaults found only defaultValue docs about other components.

Acceptance notes (not changed here)

  • The second form chain. apps/console/src/components/FormPage.tsx serves /forms/:name and /f/:slug. It seeds through its own readPrefill, which still reads defaultValue alone, so an option-default select there would still open empty. This is a reading of the code, not a measured failure. It is outside this claim's surface (apps/console). Sharing the rule would need a published helper, which would be a Clause-② question. Carrier: none named; left to the seat.
  • Kanban InlineQuickAdd and the calendar's quick-create payload read defaultValue the same way. They were not measured, and no carrier is named.

Gates, at head 6da0e6e0b

  • pnpm exec vitest run on:

    • the new pin;
    • the five existing tests that import schemaDefaults (createDefaults, currentUserDefault, entrySurface-6059, initialRecordMerge-9760, parameterTypesNameable-7324);
    • column-identity.ratchet.test.ts.

    Result: Test Files 7 passed (7), Tests 141 passed (141).

  • pnpm --filter @object-ui/plugin-form type-check (tsc --noEmit && tsc -p tsconfig.test.json) exits 0, after building the @object-ui/plugin-form^... closure. --listFiles counts the new test once.

  • pnpm exec eslint on the two touched source/test files: 2 files, 0 errors, 0 warnings. ESLint config has no type-aware linting, so untouched files cannot change verdict.

  • All exit 0:

    • node scripts/check-changeset-presence.mjs
    • node scripts/check-changeset-no-major.mjs
    • node scripts/check-changeset-overwrite.mjs
    • pnpm check:changeset-claims
    • pnpm check:pending-changeset-literals
    • pnpm check:spec-symbols
    • pnpm check:new-line-citations (0 new)
    • pnpm check:control-bytes
    • node scripts/check-test-path-roots.mjs
    • node scripts/check-vi-mock-override-shape.mjs
    • node scripts/check-doc-links.mjs
  • Not run locally (CI): the repo-wide pnpm lint / pnpm check, readme-exports (no export list changed) and doc-snippet-types (no code fence added).

Changeset: .changeset/11914-select-option-default.md, @object-ui/plugin-form patch.

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


Generated by Claude Code

claude added 4 commits October 8, 2026 08:45
…efault: true

A field that declares no `defaultValue` but marks one option
`default: true` opened on the "Select an option" placeholder, while a
create that omitted the field stored the marked option: the server's
insert path falls back to it since objectstack#7246. `schemaDefaultValues`,
the one function every create-form container seeds through, now reads the
option list the same way the engine's `resolveOptionDefault` does: only
when `defaultValue` is absent (== null), first marked option on a
single-valued field, every marked option as an array on a multi-valued one
(`isMultiValueField`). Edit forms and caller seeds are unchanged.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
…t: true

The README said an option's `default: true` leaves a create form empty
because the server reads `defaultValue` alone. The server falls back to the
marked option, and the form now does too, so the table row and the
paragraph under it state the rule the form applies. Adds the patch
changeset for the fix.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
…rce double

Drops the `as any` casts from the new pin: the container schemas are
typed by `ModalFormSchema` and `ObjectFormSchema`, and the data-source
double is a named partial.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
…ault

A `multiple` flag on a type outside the multi-valued sets keeps the
seeded default a scalar, and an option whose value is spelled
`current_user` seeds that literal, never the acting user's id: both
are what the engine stores for an omitted field.

Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation plugin tests labels Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

❌ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 336 chunks) 3307.6 KB 3307.0 KB
Main entry chunk (gzip) 71.3 KB 350 KB
Entry file index-lrs5-G1a.js —
Status FAIL —

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.

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ❌ over its ceiling
Per-chunk ceilings ✅ pass
Per-chunk membership (declared packages) ✅ pass
Ceiling sensitivity (headroom) ✅ pass
Ceiling freshness (checkout vs. base branch) ✅ pass

📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 17.82KB 6.58KB
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.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 586.28KB 141.14KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 266.92KB 67.47KB
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) 38.37KB 10.31KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.50KB 11.82KB
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) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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) 53.39KB 15.52KB
plugin-charts (index.js) 84.71KB 23.25KB
plugin-chatbot (index.js) 199.63KB 47.46KB
plugin-dashboard (index.js) 144.82KB 39.17KB
plugin-designer (index.js) 231.46KB 48.87KB
plugin-detail (index.js) 248.57KB 65.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.11KB 45.88KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 248.06KB 68.77KB
plugin-kanban (index.js) 52.17KB 16.37KB
plugin-list (index.js) 117.45KB 29.33KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.10KB 11.81KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.07KB 22.93KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
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.08KB 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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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-components.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.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 337 chunks) 3308.2 KB 3312.0 KB
Main entry chunk (gzip) 71.4 KB 350 KB
Entry file index-Rhijnp9M.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) 17.82KB 6.58KB
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.29KB 0.66KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 587.49KB 141.58KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 266.92KB 67.47KB
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) 41.50KB 11.82KB
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) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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) 53.39KB 15.52KB
plugin-charts (index.js) 84.71KB 23.25KB
plugin-chatbot (index.js) 199.63KB 47.46KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 231.46KB 48.87KB
plugin-detail (index.js) 248.57KB 65.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.11KB 45.88KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 248.06KB 68.79KB
plugin-kanban (index.js) 52.17KB 16.37KB
plugin-list (index.js) 117.58KB 29.37KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.10KB 11.81KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.07KB 22.93KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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-components.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.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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
objectstack-fleet Bot marked this pull request as ready for review October 8, 2026 12:19
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit ccddd11 Oct 8, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11914-select-default-option branch October 8, 2026 12:37
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 9, 2026
…1) and the Interfaces page-create (objectui#11932) (objectstack-ai#11967)

Part of objectstack-ai#11861
Re-lands objectui#11823 step 3: objectui#11932, the Studio Interfaces
page-create (seat `domain:ui#3`). That card stays open.
Clause-②: no
Held as a draft until objectui#11949 (the +5,120 B allowance, ruling
`6056819248` step 2) lands.
When this PR was opened, objectui#11949 was already on `main` as
`1c51e973b`, and this branch has merged it.

## What this is

A plain `git revert 3c888c6`, followed by merges of `main`. `3c888c6` is
the rollback PR objectui#11956, a single-parent squash, so `-m 1` does
not apply. It brings back:

- objectui#11931: Studio's validation "New" menu opens on common rules,
with the rule types under "Advanced". This is the validation-rule entry
of objectui#11861.
- objectui#11932: objectui#11823 step 3. The Interfaces pillar creates a
page and opens it on its source beside a live preview.

Claim `6057967120` on objectui#11861 · review `6057399892` on
objectui#11937 · ruling `6056819248` on objectui#11942.

## Tree proof

- The revert commit `7eeffd29b` has the tree of `f3a0488` (`011fe521e`),
so `git diff f3a0488 7eeffd2 --stat` prints nothing.
- `.changeset/11937-eager-budget-rollback.md` was added by `3c888c6` and
never existed at `f3a0488`. Its removal therefore shows against
`3c888c6`, not against `f3a0488`.
- Against `main`, the branch changes the 15 paths `3c888c6` changed, and
no other path.
- Twelve of the 15 hold their `f3a0488` blob byte for byte. The other
three were also changed on `main` after `3c888c6`, and they carry both
intents (next section).

## Merges of main, and the conflicts

The branch merged `main` five times: at `1c51e973b`, `d73d98770`,
`70e3d7721`, `ccc2824cf` and `247f50349`. Only two of the PRs these
brought in touch a restored file.

**objectui#11945** (objectui#11923, the *Runs on* row), merged at
`70e3d7721`.
- One conflicting hunk, in the import block of
`ObjectValidationsPanel.tsx`. This side imports `validationPresets.js`;
`main` imports `ScriptValidationSchema` / `ScriptValidationParsed` from
`@objectstack/spec/data`. Both lines are kept.
- Two files merged without conflict:
- `metadata-admin/i18n.ts`: `main` removes the
`engine.studio.rules.event.delete` row, en and zh. It stays removed.
- the `newRuleWaits-11820` pin: `main` asserts there is no Delete box.
That assertion stays.
- Check, per file: the changed lines of the merge against `main` equal
the re-land's own changed lines (`3c888c6..f3a0488`). The changed lines
of the merge against this branch's previous head equal objectui#11945's
own diff. Both comparisons were identical for all three files.

**objectui#11935** (objectui#11894, typed is-empty operators), merged at
`247f50349`.
- Two conflicting hunks, both in `ObjectValidationsPanel.tsx`. Each side
added the same `FieldOpt` member, `type`.
- The interface keeps one `type`, `main`'s `multiple` and the presets'
`system`. One doc comment names both readers of `type`.
- The field mapping keeps one `type` line, `main`'s `multiple` line with
its comment, and the presets' `system` line.
- `i18n.ts` merged without conflict, and both sides' rows are kept.
- The same check, run on this merge, leaves only the shared `type`
member and the merged comments as residual lines.

`main` moved on after `247f50349` (objectui#11961, objectstack-ai#11962, objectstack-ai#11944). None
of those touches any of the 15 paths, so they are not merged here.

## Changesets

- Restored: `.changeset/11861-validation-presets.md` and
`.changeset/11823-page-create.md`, both `@object-ui/app-shell: patch`.
- Removed: `.changeset/11937-eager-budget-rollback.md`
(`@object-ui/app-shell: patch`). This re-land supersedes it.
- `check-changeset-overwrite` is report-only and exits 0. It reports one
pre-existing changeset deleted, with `@object-ui/app-shell` "GONE from
the declaration" of that file.
- The package still bumps, because both restored changesets declare it.
This is the gate's case 3: a changeset superseded by a replacement in
the same change.

## Gates, on head `fb0c91d45` (every merge above included)

Tests use the repo-root `pnpm exec vitest run` and run under the shared
verify lock.

- **Named set:** 98 files and 631 tests, all passed. It covers:
- all eight `ObjectValidationsPanel*` suites, including objectui#11945's
`runsOn-11923` and objectui#11935's `typedEmptyOps-11894`;
- every test file that imports `interfaceCreate` or
`StudioDesignSurface`;
  - `column-identity.ratchet.test.ts`;
- the `main` pins next to the conflicts:
`ConditionBuilder.typedEmptyOps-11894`, `PagePreview.pageKind-11933` and
`SourcePageEditor.pageKind-11933`.
- **Widened set:** 87 files and 1,103 tests, all passed. It covers every
other test that imports `validationPresets`, `ObjectValidationsPanel` or
the designer string table `metadata-admin/i18n.ts`.
- `pnpm --filter @object-ui/app-shell type-check` passes, after a turbo
build of the app-shell dependency closure (28 of 28 tasks).
- Each of these gates exits 0:
  - `check:i18n-keys`, `check:i18n-designer-parity`, `check:i18n-drift`;
- `check-changeset-presence`, `check-changeset-fixed`,
`check-changeset-no-major`, `check:changeset-claims`,
`check:pending-changeset-literals`, `check-changeset-overwrite`
(report-only, see above);
  - `check:unreferenced-sources`.
- eslint on the 11 touched source and test files reports 0 errors and 22
warnings. The repo sets no `--max-warnings`. The warnings are the ones
already in these files at `f3a0488`, and the merge adds none.
- `check-governed-queue-guard --test` reports NOT GOVERNED: none of the
15 paths is on a governed surface.
- Not run: the console build. CI's `Bundle Analysis` measures the
first-load bytes against the ceiling that objectui#11949 raised.
`scripts/check-eager-closure-budget.mjs` is not touched.
- Reference point: on its push run, `f3a0488` (the tree this re-land
restores) had 66 check runs succeed, 6 skipped and 1 fail, `Bundle
Analysis`. That is 73 of 73 runs read.

---

_Generated by [Claude
Code](https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation plugin tests

Projects

None yet

2 participants