Skip to content

fix(plugin-form): keep a 1rem viewport gutter on lg/xl ModalForm dialogs from sm up (objectui#12593) - #12598

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12593-dialog-viewport-margin
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12593-dialog-viewport-margin

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12593
Clause-②: no

What changed

ModalForm's two bounded wide sizes are lg (sm:max-w-2xl, 672px) and xl (sm:max-w-5xl, 1024px). They now also read ONE shared class, BOUNDED_SIZE_VIEWPORT_GUTTER = 'sm:w-[calc(100%-2rem)]', defined once in ModalForm.tsx next to modalSizeClasses.

  • The dialog is now the smaller of its max width and the window less 2rem.
  • The primitive's left-[50%] and translate-x-[-50%] centre it, so it keeps 1rem on each side at every width from sm up.
  • Above the max width plus 2rem (1056px for xl, 704px for lg), each size is exactly as wide as before.

The class strings stay literal in source, so Tailwind's scanner sees both. The 2rem literal is written once.

Unchanged:

There is no edit to packages/components/**, custom/mobile-dialog-content.tsx, any app-shell host or any other dialog. Nothing is added: no prop, export, type member or modalSize value.

Files:

  • packages/plugin-form/src/ModalForm.tsx: the constant and the lg / xl rows of the map;
  • new pin packages/plugin-form/src/__tests__/modalViewportGutter-12593.test.tsx;
  • .changeset/12593-modal-viewport-gutter.md (@object-ui/plugin-form, patch).

Mechanism assumptions, as measured

  • A1: the class is emitted. Holds. I ran the console's own Tailwind step: @tailwindcss/postcss, the plugin apps/console/postcss.config.js names, over apps/console/src/index.css. That file's @source lines include packages/plugin-form/src and exclude __tests__.
    • The emitted sheet has width: calc(100% - 2rem) under the selector for sm:w-[calc(100%-2rem)].
    • That rule sits inside the sm media query (a width of at least 40rem), after the base .w-full rule.
    • At the base commit, no tracked source spells the class: git grep exits 1. The control, sm:max-w-5xl in ModalForm.tsx, exits 0. So the emitted rule comes from this change.
  • A2: the width resolves against the viewport. Holds; 100% was chosen. The dialog is fixed, so 100% is its containing block: the viewport less any classic scrollbar, the same box left-[50%] centres in.
    • Measured in Chromium with classic scrollbars: I turned off Playwright's --hide-scrollbars and made the page scroll, which gives a 10px scrollbar.
    • The 100% form gives 16/16px gutters at 1024 and at 768.
    • A calc(100vw - 2rem) width, tried in the harness only, gives 11/11px: each gutter loses half the scrollbar.
  • A3: the 12521 pins need new class strings. Does not hold; they are unchanged and keep their meaning.
    • The chosen shape keeps sm:max-w-5xl / sm:max-w-2xl as their own tokens and adds a separate width token.
    • So toContain('sm:max-w-5xl') (a heavy object opens xl) and toContain('sm:max-w-2xl') (a light one opens lg) pass as written, in dialogDefaultLayout-12521.test.tsx and in app-shell's AppContent.recordDialogInterimBound-12521.test.tsx.
    • A rewrite would only be needed for a min(...) max-width shape. That shape writes the 2rem literal once per size, so it was not taken.

Real-layout reading (Chromium, static harness)

The harness is the dialog element's class list from a real ModalForm render, after tailwind-merge, over the console's emitted CSS. It ran in headless Chromium 1194 at a viewport height of 900. "Before" is the same class list without the gutter token. Each cell is width · left/right gutter, in px.

Viewport xl before xl after lg before lg after sm default full
1440 1024 · 208/208 1024 · 208/208 672 · 384/384 672 · 384/384 384 · 528/528 512 · 464/464 1368 · 36/36
1100 1024 · 38/38 1024 · 38/38 672 · 214/214 672 · 214/214 384 · 358/358 512 · 294/294 1045 · 27.5/27.5
1056 1024 · 16/16 1024 · 16/16 672 · 192/192 672 · 192/192 384 · 336/336 512 · 272/272 1003.19 · 26.41/26.41
1024 1024 · 0/0 992 · 16/16 672 · 176/176 672 · 176/176 384 · 320/320 512 · 256/256 972.8 · 25.6/25.6
768 768 · 0/0 736 · 16/16 672 · 48/48 672 · 48/48 384 · 192/192 512 · 128/128 729.59 · 19.2/19.2
704 704 · 0/0 672 · 16/16 672 · 16/16 672 · 16/16 384 · 160/160 512 · 96/96 668.8 · 17.6/17.6
700 700 · 0/0 668 · 16/16 672 · 14/14 668 · 16/16 384 · 158/158 512 · 94/94 665 · 17.5/17.5
640 640 · 0/0 608 · 16/16 640 · 0/0 608 · 16/16 384 · 128/128 512 · 64/64 608 · 16/16
639 639 · 0/0 639 · 0/0 639 · 0/0 639 · 0/0 639 · 0/0 639 · 0/0 639 · 0/0
390 390 · 0/0 390 · 0/0 390 · 0/0 390 · 0/0 390 · 0/0 390 · 0/0 390 · 0/0

The sm, default and full columns read the same before and after. Their class lists do not change.

What the landing seat's browser reading should show

HotCRM Leads → New. It is a field-heavy create, so it opens xl, as the card measured. The numbers are predicted from the harness above:

Viewport Dialog width Left gutter Right gutter
1440 × 900 1024px, unchanged 208px 208px
1024 × 768 992px 16px 16px
768 736px 16px 16px
390 390px, the full-screen sheet, unchanged 0 0

At 1024 and 768, the card measured the base at 1024px and 768px, both at x = 0. A reading that still shows x = 0 means the console CSS it served was not rebuilt from this head.

Tests and gates

Run on head c57843d95d unless a line names another commit. Heavy runs went through the shared verify lock. CI runs the full farm.

  • New pin modalViewportGutter-12593.test.tsx, 4 tests:
    • lg and xl each carry exactly one sm-tier width, the same gutter token, and keep their own max width;
    • the field-heavy default (no authored size) carries it;
    • against default, lg / xl differ only in sm:-prefixed tokens, and the phone sheet and height classes are still present;
    • CONTROL: sm, default and full read no gutter.
  • Every @object-ui/plugin-form suite: pnpm exec vitest run --maxWorkers=2 packages/plugin-form/ gave Test Files 187 passed (187), Tests 2291 passed, 1 skipped (2292). The run printed c57843d95d as its head. The new pin plus both 12521 files, including app-shell's, also ran on their own: 3 files, 26 tests passed.
  • Type-check: pnpm turbo run build --filter='@object-ui/plugin-form^...' --concurrency=2 exited 0 (11 tasks). Then pnpm --filter @object-ui/plugin-form type-check (tsc --noEmit && tsc -p tsconfig.test.json) exited 0. --listFiles shows that tsconfig.test.json compiles the new pin.
  • ESLint on the two changed source files exited 0, with 0 errors. The new pin has no warnings; ModalForm.tsx's warnings were all there before this change.
  • Census and ratchet sweep, 8 files, 173 tests passed:
    • product-neutral-renderer.ratchet, no-component-any-cast.ratchet, iconOnlyButtonCensus-12143, ariaLabelLiteralCensus-12145;
    • changeset-polarity-census, check-changeset-no-major;
    • test-file-timings, test-shard-partition.
  • Changeset gates, each exit 0: check-changeset-presence (1 changeset declared for 2 source files of 1 released package), check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims, check:pending-changeset-literals, census:changeset-polarity.
  • check:control-bytes and check:new-line-citations exit 0 on c57843d95d, with 0 new citations.
  • Other gates, each exit 0: check:phantom-deps, check:self-import, check:unreferenced-sources, check:handler-key-reads, check:metadata-write-doors, check:i18n-keys, check:published-tsconfig-exclude, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:shell-escape-residue.
  • Governed surface: check-governed-queue-guard --test on the three paths answers NOT GOVERNED.

Ablation

The fix was committed first. The mutation went through ablation-replace with a trapped restore: the constant's value 'sm:w-[calc(100%-2rem)]' became ''. On disk the anchor count went from 1 to 0 and the blob changed.

  • The three margin pins went red: lg and xl both carry the one shared gutter, a field-heavy dialog … carries it and below sm nothing changes ….
  • The CONTROL pin stayed green: Tests 3 failed, 1 passed (4).
  • After the restore, the blob equals HEAD and git diff HEAD is empty.

Acceptance notes

  • Out of scope, the same defect in another dialog: app-shell's useActionModal. This is the console's type: 'modal' action path, and the dispatch keeps it off this PR.
    • Its SIZE_CLASS maps lg to sm:max-w-2xl and xl to sm:max-w-5xl on the Shadcn DialogContent primitive's w-full max-w-lg.
    • A page-target modal with no declared size resolves to xl.
    • Same harness, over the same console CSS: 1440 gives 1024 · 208/208, 1024 gives 1024 · 0/0, and 768 gives 768 · 0/0.
    • Named producer: objectstack examples/app-showcase's showcase_quick_view (type: 'modal', target page showcase_component_gallery, no size).
    • It is reported to the seat to file. It is not filed from here, and not fixed here.
  • The dialog-size paragraph in content/docs/plugins/plugin-form.mdx states no widths, so nothing in it becomes false. No docs edit.

Generated by Claude Code

…ogs from sm up

An lg (672px) or xl (1024px) dialog took the primitive's w-full, so on any
window between sm and its max width it was as wide as the window, at x = 0.
Both bounded wide sizes now also read one shared class,
sm:w-[calc(100%-2rem)], under their own max-w. sm, default and full, and the
phone sheet below sm, are unchanged.

Claude-Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB
Co-authored-by: Claude <noreply@anthropic.com>
…zes (objectui#12593)

Claude-Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB
Co-authored-by: Claude <noreply@anthropic.com>
…bjectui#12593)

Also words the 100vw note exactly: each gutter would lose half the
scrollbar's width, as measured in Chromium with classic scrollbars.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

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

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Seat ACCEPT: objectui PR #12598 at c57843d95d · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-16T03:04Z

Verdict: ACCEPT. Reviewed against:

  • the card objectui#12593;
  • its triage grade 6206287250;
  • the claim 6206600248;
  • the dev report 6206971611.

No contract-review face applies:

  • Clause-②: no on line 2;

  • no type, prop, export or modalSize value is added;

  • none of the 3 files is a published-schema or governed path.

  • Shape: draft; base main; assignee sunhaolin. Line 1 is Fixes #12593, the body's only closing keyword. 3 files, +203/−2. One @object-ui/plugin-form patch changeset, not major.

  • The fix:

    • One module constant in ModalForm.tsx, BOUNDED_SIZE_VIEWPORT_GUTTER = 'sm:w-[calc(100%-2rem)]', read by the lg and xl rows of modalSizeClasses only.
    • The dialog is the smaller of its own max width and the window less 2rem. The primitive's left-[50%] and translate-x-[-50%] centre it with 1rem on each side.
    • sm, default and full, the phone sheet below sm, and the height rules are unchanged.
  • Mechanism assumptions, measured:

    • A1: the console's own Tailwind step emits width: calc(100% - 2rem) inside @media (width >= 40rem), and at the base the class is absent.
    • A2: 100% was chosen over 100vw. With a classic 10 px scrollbar, 100% gives 16/16 gutters and 100vw gives 11/11.
    • A3, measured false and accepted: the objectui#12521 pins keep sm:max-w-5xl / sm:max-w-2xl as their own tokens, so they pass unedited with their meaning intact.
  • Pins: modalViewportGutter-12593.test.tsx, 4 tests:

    • lg and xl carry the one gutter token and keep their max width;
    • the field-heavy default carries it;
    • against default, lg and xl differ only in sm: tokens;
    • CONTROL: sm, default and full read no gutter.
  • Ablation: emptying the constant turns the 3 margin pins red, and the CONTROL stays green. The restore is proven blob-identical to the head.

  • Real layout (the dev's Chromium reading): the class list comes from a real ModalForm render, over the CSS the console's own Tailwind step emits. Width · left/right gutter, in px:

    Viewport xl before xl after
    1440 1024 · 208/208 1024 · 208/208
    1024 1024 · 0/0 992 · 16/16
    768 768 · 0/0 736 · 16/16
    390 390 · 0/0 (sheet) 390 · 0/0 (sheet)

    lg at 700 px is 668 · 16/16, and it stays 672 above 704 px. These are exactly the card's three pins. The seat accepts this reading in place of a served HotCRM reading:

    • The defect and the fix are a pure function of the class list and the emitted CSS, and both were read from real sources.
    • The PR's "What the landing seat's browser reading should show" table stays for a post-landing check.
  • Gates:

    • Every @object-ui/plugin-form suite: 2291 passed, 1 skipped.
    • The objectui#12521 pins on both sides: 26 passed.
    • Type-check after a closure build, the census and ratchet sweep (173), the changeset gates, the import and mock gates, check:control-bytes, check:new-line-citations and eslint: all exit 0. check-governed-queue-guard --test reports NOT GOVERNED.
    • CI on c57843d95d: 36 runs, 33 success, 3 expected skips (dependabot and the coverage pair), 0 failures. mergeable_state is clean. The path face (get_files) is .changeset/, packages/plugin-form/src/ and its __tests__/: no governed path, 205 lines.
  • Accepted deviation: the shared value is a constant declared directly above modalSizeClasses, not inside the map. It is the same file, and no other symbol is touched.

  • Out of scope:

    • Filed objectui#12603 (finding): the same edge-to-edge defect in the action modal's SIZE_CLASS (useActionModal.tsx; its xl was measured at 1024 · 0/0 and 768 · 0/0) and in six more wide centred DialogContent sites, enumerated there with an ask for one shared rule and a census pin.
    • Acceptance notes: content/docs/plugins/plugin-form.mdx states no widths, so nothing there becomes false.
    • Housekeeping noted, not repository content: a 5-byte /build.pid the dev left at the container root, outside every repository.

Landing: ready and auto-merge now. Its merge closes objectui#12593.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 03:05
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 03:05
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 85e8961 Oct 16, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12593-dialog-viewport-margin branch October 16, 2026 03:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants