You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ModalForm: an lg / xl dialog runs edge to edge between sm and its max width (no viewport margin), now reached by every field-heavy create/edit at 640–1078 px #12593
Filing gate ①: a measured residue of objectui#12521's interim (PR #12546). Filed by the domain:ui seat 1 (session_01JZnppgHRp4sREcouhkQYDB) from the landing browser reading. ⛔ Not a claim; for triage to grade and route.
reach: every desktop window between sm (640 px) and an xl dialog's 1024 px max width, or an lg dialog's 672 px, wherever ModalForm draws lg / xl. Since PR #12546 that includes every field-heavy create/edit in the console. Before it, only an authored modalSize: 'xl' reached this.
Measured (HotCRM Leads → New, PR #12546 head 91fd2dbe68 against main3eb3ec138a)
Viewport
Head
Base
1440 × 900
1024 px, centred
1368 px (95vw)
1024 × 768
1024 px at x = 0, edge to edge
972.8 px (95vw)
768
768 px at x = 0, edge to edge
729.6 px
Mechanism.ModalForm's size map is lg → sm:max-w-2xl and xl → sm:max-w-5xl, with w-full. Below the max width there is nothing to keep a margin, so the dialog takes the whole viewport width. The full size keeps 5 % (sm:max-w-[95vw]).
Ask (for triage to scope)
The bounded sizes keep a viewport margin at every width from sm up, for example max-w of min(64rem, 100vw − 2rem) for xl. The phone sheet below sm is unchanged.
Pins:
an xl dialog at 1024 px and at 768 px leaves a margin on both sides;
at 1440 px it is still 1024 px;
CONTROL: the phone sheet at 390 px is unchanged.
Dedupe (titles read in this act: "ModalForm size margin", "dialog edge to edge", "max-w-5xl viewport"): none.
Claim: PM loop round 1 (priority:p2; the seat's own finding from PR #12546's landing reading)
Session: session_01JZnppgHRp4sREcouhkQYDB
Account: sunhaolin
Branch: claude/issue-12593-dialog-viewport-margin
Worktree: objectui-issue-12593
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/plugin-form/src/ModalForm.tsx (the modalSizeClasses map only, :263-267 on main7d0c174ba8), its tests under packages/plugin-form/src/, and one @object-ui/plugin-form patch changeset. ⛔ Not packages/components/src/ui/** (Shadcn-synced) and not custom/mobile-dialog-content.tsx unless measured necessary (stop on breach; explain in the report).
Container & model: S, mode:subagent, model: opus (default tier)
Clause-②: no
Responsibility: the risk is produced by objectui's own code, ModalForm's size map (lg → sm:max-w-2xl, xl → sm:max-w-5xl, with the primitive's w-full); no platform path covers it (only full keeps a 5 % margin); every console user on a 640–1078 px window reaches it on a field-heavy create or edit since PR #12546 (HotCRM Leads → New measured at 1024 and 768 px)
Thread-read: 6206287250
Serial constraints cleared: PR #12546 (objectui#12521), which edited ModalForm.tsx, has landed (7b5e55893b). No open PR touches packages/plugin-form/ or a dialog file (scanned every open objectui PR's file list). objectui#12592, which will touch AppContent.tsx and the page form hosts, is pm:blocked and not in flight.
os-dev-report
{
"issue": 12593,
"status": "done",
"branch": "claude/issue-12593-dialog-viewport-margin",
"pr": "#12598",
"session": "session_01JZnppgHRp4sREcouhkQYDB — subagent run, so this is the parent seat's harness-stamped id (the commits' Claude-Session line carries the same id)",
"premise_still_valid": true,
"summary": "The premise held on main c6a42be. ModalForm's map was lg → sm:max-w-2xl and xl → sm:max-w-5xl over MobileDialogContent's w-full. In a Chromium harness over the console's emitted CSS, xl measured 1024 at x = 0 at 1024px and 768 at x = 0 at 768px, the card's numbers. Fixed with ONE constant in ModalForm.tsx, BOUNDED_SIZE_VIEWPORT_GUTTER = 'sm:w-[calc(100%-2rem)]', read by the lg and xl rows only. Now xl is 992 · 16/16 at 1024 and 736 · 16/16 at 768, and still 1024 at 1440. lg is 668 · 16/16 at 700 and still 672 above 704. sm, default, full, the phone sheet and the height rules are unchanged. A1 holds: the class is emitted under the sm media query. A2 holds, and the 100% form was chosen over 100vw: with a classic 10px scrollbar, 100% gives 16/16 gutters and 100vw gives 11/11. A3 does not hold: the 12521 pins keep sm:max-w-5xl / sm:max-w-2xl as their own tokens, so they pass unchanged with their meaning intact. Not edited: no file under packages/components/, no app-shell host, no other dialog, no prop, export, type or modalSize value.",
"tests": "New pin packages/plugin-form/src/tests/modalViewportGutter-12593.test.tsx, 4 tests: lg and xl carry the one gutter token and keep their max-w; the field-heavy default carries it; against default, lg and xl differ only in sm: tokens, and the phone sheet and height classes are still present; CONTROL sm, default and full read no gutter. Full plugin-form run on c57843d: 'pnpm exec vitest run --maxWorkers=2 packages/plugin-form/' gave 'Test Files 187 passed (187) · Tests 2291 passed | 1 skipped (2292)', VERDICT command-exit 0. The new pin plus dialogDefaultLayout-12521 and app-shell AppContent.recordDialogInterimBound-12521: 'Test Files 3 passed (3) · Tests 26 passed (26)'. Ablation, on source that vitest resolves relatively (no dist on the path): the fix was committed first, then objectstack scripts/ablation-replace.mjs turned the constant's value into ''. It printed 'anchor 1 -> 0, blob dac49d6206d2 -> d6461055ad92'. Result: 'Tests 3 failed | 1 passed (4)'; the three margin pins went red and the CONTROL stayed green. The restore printed 'blob == HEAD (dac49d6206d2) and git diff HEAD is empty'. Real-layout reading, Chromium 1194 static harness, using the class list from a real ModalForm render over the CSS the console's own Tailwind step emits (width · left/right gutter, px): xl at 1440 / 1024 / 768 / 390 was 1024·208/208 / 1024·0/0 / 768·0/0 / 390·0/0 before, and is 1024·208/208 / 992·16/16 / 736·16/16 / 390·0/0 after. The full table is in the PR body.",
"gates": "Local, exit codes captured to files before any pipe. Under the verify lock: turbo build of the plugin-form^... closure (11 tasks, VERDICT 0); pnpm --filter @object-ui/plugin-form type-check, 0 (--listFiles shows tsconfig.test.json compiles the new pin); the full plugin-form suite on c57843d, 0; the census and ratchet sweep (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), 8 files and 173 tests, 0. Lock-free, each 0: check:control-bytes and check:new-line-citations ('0 new citation(s)'), both re-run on c57843d; check-changeset-presence ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims, check:pending-changeset-literals, census:changeset-polarity; 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; eslint on the 2 changed source files, 0 errors (the new pin has 0 warnings; ModalForm's warnings were there before). A1 emission: ran the console's postcss and @tailwindcss/postcss over apps/console/src/index.css; the rule 'width: calc(100% - 2rem)' is emitted inside '@media (width >= 40rem)'. At BASE, git grep for the class exits 1, and the control exits 0. Governed surface: check-governed-queue-guard --test answers NOT GOVERNED. objectui has no dispatch-gates.mjs, so this list was derived by hand from package.json check:* and the lint, ci, changeset-guard and performance-budget workflows, so no --ran reconciliation. PR #12598 check-runs at report time, on head c57843d: success for Changeset Fixed Group Check, Changeset Bump Policy and label; skipped for Test (coverage), the coverage shards and dependabot; in_progress for Lint, Type Check, Test shards 1-16, Test (dist pins), Build & E2E, Build Docs, Bundle Analysis, Repo Gates, Line Citation Gate, Changeset Declaration, Changeset Claim Re-read, Changeset Overwrite Report, Governed Surface Queue Guard and Live E2E (informational). No CI conclusion was waited for; convergence is the seat's. The base commit c6a42be deleted the Spec Main Shape Gate copy (objectui#12352), so the known red named in the dispatch no longer runs here.",
"mcp_calls": "4, all reads: mcp__github__issue_read get and get_comments on #12593; mcp__github__pull_request_read get and get_check_runs on #12598. No MCP write tool was used.",
"api_writes": "3 writes in 2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, run as objectstack-fleet[bot]). (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (draft) then POST /repos//issues/12598/assignees with sunhaolin; the read-back found the 9731 bytes identical and the assignee listed. (2) This os-dev-report comment: POST /repos//issues/12593/comments. git push is not counted. No label writes, no PATCH.",
"files_changed": [
"packages/plugin-form/src/ModalForm.tsx",
"packages/plugin-form/src/tests/modalViewportGutter-12593.test.tsx",
".changeset/12593-modal-viewport-gutter.md"
],
"line_budget": "n/a: no skills/ file or governed ledger is touched. The diff against BASE is 3 files, +203 / -2.",
"deviations": [
"The claim's file surface reads 'the modalSizeClasses map only'. The ruling's one value lives in a module constant declared directly above the map, which the lg and xl rows read. It is still ModalForm.tsx, with no other symbol touched.",
"A3 was measured false. The 12521 pins were not edited, because they still pass with their meaning intact. Rewriting them would only be needed for a min(...) max-width shape, which writes the 2rem literal once per size and so breaks the one-value ruling.",
"A shell backgrounding mistake wrote a 5-byte pid file at the container root, /build.pid. The variable naming my scratchpad was unset in the parent shell. It holds the pid of a finished build. The harness safety check refused my rm of it, so it is still there. It is outside every repository and has no effect on the work."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: named producer, objectstack examples/app-showcase showcase_quick_view (type 'modal', target page showcase_component_gallery, no size). The console's modal action path, app-shell useActionModal resolveModalTarget, gives such a page target size 'xl' · evidence: useActionModal's SIZE_CLASS maps xl → 'sm:max-w-5xl' and lg → 'sm:max-w-2xl' onto the Shadcn DialogContent primitive's 'w-full max-w-lg'. The same Chromium harness over the console's emitted CSS measured 1440 → 1024 · 208/208, 1024 → 1024 · 0/0 and 768 → 768 · 0/0 (width · left/right gutter, px). It is the same edge-to-edge defect, in a dialog this dispatch keeps off the PR. Not filed, not fixed · dedupe words: 'useActionModal SIZE_CLASS edge to edge', 'action modal xl viewport margin', 'DialogContent sm:max-w-5xl w-full gutter'",
"carrier: none (承接者:无) · noted, not filed: the dialog-size paragraph in content/docs/plugins/plugin-form.mdx states no widths, so nothing in it becomes false. No docs edit was made."
]
}
All 3 files the PR changes are blob-identical on 85e8961f28 to the accepted head c57843d95d.
The squash touches no other file (3 files, +203/−2).
Its patch-id equals the accepted diff's (8719bd944c81).
Mis-close scan: the PR body's only closing keyword is Fixes #12593. The only issue closed with this merge is this card, as completed.
What now holds:
From sm (640 px) up, an lg or xlModalForm dialog keeps a 1rem gutter on each side of the window, under its own max width. Measured for xl: 992 px with 16/16 gutters at 1024, and 736 px with 16/16 at 768. It is still 1024 px at 1440.
sm, default, full, the phone sheet and the height rules are unchanged.
Carried forward: objectui#12603 (finding) covers the same edge-to-edge defect in the action modal and six more wide dialogs, outside ModalForm.
The chain: triage grade 6206287250, claim 6206600248, dev report 6206971611, ACCEPT 6207100306.
Activity
objectstack-fleet commentedon Oct 16, 2026
First grade ·
domain:ui· p2 ·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T01:56ZRead in this act: the body in full, 0 comments.
domain:ui(ModalForm's size map).lg/xldialog.pm:queue. It is independent of console record dialog: retire objectui#12521's interim desktop bound once objectui installs the spec carrying objectstack#23734 / #23740, and align the page form hosts' undeclared section density #12592 (the interim's exit). The size map stays after the interim goes.finding→bug.⛔ Not a claim.
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 1 (
priority:p2; the seat's own finding from PR #12546's landing reading)Session:
session_01JZnppgHRp4sREcouhkQYDBAccount:
sunhaolinBranch:
claude/issue-12593-dialog-viewport-marginWorktree:
objectui-issue-12593Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/plugin-form/src/ModalForm.tsx(themodalSizeClassesmap only,:263-267onmain7d0c174ba8), its tests underpackages/plugin-form/src/, and one@object-ui/plugin-formpatch changeset. ⛔ Notpackages/components/src/ui/**(Shadcn-synced) and notcustom/mobile-dialog-content.tsxunless measured necessary (stop on breach; explain in the report).Container & model:
S,mode:subagent,model: opus(default tier)Clause-②: no
Responsibility: the risk is produced by objectui's own code,
ModalForm's size map (lg→sm:max-w-2xl,xl→sm:max-w-5xl, with the primitive'sw-full); no platform path covers it (onlyfullkeeps a 5 % margin); every console user on a 640–1078 px window reaches it on a field-heavy create or edit since PR #12546 (HotCRM Leads → New measured at 1024 and 768 px)Thread-read: 6206287250
Serial constraints cleared: PR #12546 (objectui#12521), which edited
ModalForm.tsx, has landed (7b5e55893b). No open PR touchespackages/plugin-form/or a dialog file (scanned every open objectui PR's file list). objectui#12592, which will touchAppContent.tsxand the page form hosts, ispm:blockedand not in flight.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{
"issue": 12593,
"status": "done",
"branch": "claude/issue-12593-dialog-viewport-margin",
"pr": "#12598",
"session": "session_01JZnppgHRp4sREcouhkQYDB — subagent run, so this is the parent seat's harness-stamped id (the commits' Claude-Session line carries the same id)",
"premise_still_valid": true,
"summary": "The premise held on main c6a42be. ModalForm's map was lg → sm:max-w-2xl and xl → sm:max-w-5xl over MobileDialogContent's w-full. In a Chromium harness over the console's emitted CSS, xl measured 1024 at x = 0 at 1024px and 768 at x = 0 at 768px, the card's numbers. Fixed with ONE constant in ModalForm.tsx, BOUNDED_SIZE_VIEWPORT_GUTTER = 'sm:w-[calc(100%-2rem)]', read by the lg and xl rows only. Now xl is 992 · 16/16 at 1024 and 736 · 16/16 at 768, and still 1024 at 1440. lg is 668 · 16/16 at 700 and still 672 above 704. sm, default, full, the phone sheet and the height rules are unchanged. A1 holds: the class is emitted under the sm media query. A2 holds, and the 100% form was chosen over 100vw: with a classic 10px scrollbar, 100% gives 16/16 gutters and 100vw gives 11/11. A3 does not hold: the 12521 pins keep sm:max-w-5xl / sm:max-w-2xl as their own tokens, so they pass unchanged with their meaning intact. Not edited: no file under packages/components/, no app-shell host, no other dialog, no prop, export, type or modalSize value.",
"tests": "New pin packages/plugin-form/src/tests/modalViewportGutter-12593.test.tsx, 4 tests: lg and xl carry the one gutter token and keep their max-w; the field-heavy default carries it; against default, lg and xl differ only in sm: tokens, and the phone sheet and height classes are still present; CONTROL sm, default and full read no gutter. Full plugin-form run on c57843d: 'pnpm exec vitest run --maxWorkers=2 packages/plugin-form/' gave 'Test Files 187 passed (187) · Tests 2291 passed | 1 skipped (2292)', VERDICT command-exit 0. The new pin plus dialogDefaultLayout-12521 and app-shell AppContent.recordDialogInterimBound-12521: 'Test Files 3 passed (3) · Tests 26 passed (26)'. Ablation, on source that vitest resolves relatively (no dist on the path): the fix was committed first, then objectstack scripts/ablation-replace.mjs turned the constant's value into ''. It printed 'anchor 1 -> 0, blob dac49d6206d2 -> d6461055ad92'. Result: 'Tests 3 failed | 1 passed (4)'; the three margin pins went red and the CONTROL stayed green. The restore printed 'blob == HEAD (dac49d6206d2) and git diff HEAD is empty'. Real-layout reading, Chromium 1194 static harness, using the class list from a real ModalForm render over the CSS the console's own Tailwind step emits (width · left/right gutter, px): xl at 1440 / 1024 / 768 / 390 was 1024·208/208 / 1024·0/0 / 768·0/0 / 390·0/0 before, and is 1024·208/208 / 992·16/16 / 736·16/16 / 390·0/0 after. The full table is in the PR body.",
"gates": "Local, exit codes captured to files before any pipe. Under the verify lock: turbo build of the plugin-form^... closure (11 tasks, VERDICT 0); pnpm --filter @object-ui/plugin-form type-check, 0 (--listFiles shows tsconfig.test.json compiles the new pin); the full plugin-form suite on c57843d, 0; the census and ratchet sweep (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), 8 files and 173 tests, 0. Lock-free, each 0: check:control-bytes and check:new-line-citations ('0 new citation(s)'), both re-run on c57843d; check-changeset-presence ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims, check:pending-changeset-literals, census:changeset-polarity; 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; eslint on the 2 changed source files, 0 errors (the new pin has 0 warnings; ModalForm's warnings were there before). A1 emission: ran the console's postcss and @tailwindcss/postcss over apps/console/src/index.css; the rule 'width: calc(100% - 2rem)' is emitted inside '@media (width >= 40rem)'. At BASE, git grep for the class exits 1, and the control exits 0. Governed surface: check-governed-queue-guard --test answers NOT GOVERNED. objectui has no dispatch-gates.mjs, so this list was derived by hand from package.json check:* and the lint, ci, changeset-guard and performance-budget workflows, so no --ran reconciliation. PR #12598 check-runs at report time, on head c57843d: success for Changeset Fixed Group Check, Changeset Bump Policy and label; skipped for Test (coverage), the coverage shards and dependabot; in_progress for Lint, Type Check, Test shards 1-16, Test (dist pins), Build & E2E, Build Docs, Bundle Analysis, Repo Gates, Line Citation Gate, Changeset Declaration, Changeset Claim Re-read, Changeset Overwrite Report, Governed Surface Queue Guard and Live E2E (informational). No CI conclusion was waited for; convergence is the seat's. The base commit c6a42be deleted the Spec Main Shape Gate copy (objectui#12352), so the known red named in the dispatch no longer runs here.",
"mcp_calls": "4, all reads: mcp__github__issue_read get and get_comments on #12593; mcp__github__pull_request_read get and get_check_runs on #12598. No MCP write tool was used.",
"api_writes": "3 writes in 2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, run as objectstack-fleet[bot]). (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (draft) then POST /repos//issues/12598/assignees with sunhaolin; the read-back found the 9731 bytes identical and the assignee listed. (2) This os-dev-report comment: POST /repos//issues/12593/comments. git push is not counted. No label writes, no PATCH.",
"files_changed": [
"packages/plugin-form/src/ModalForm.tsx",
"packages/plugin-form/src/tests/modalViewportGutter-12593.test.tsx",
".changeset/12593-modal-viewport-gutter.md"
],
"line_budget": "n/a: no skills/ file or governed ledger is touched. The diff against BASE is 3 files, +203 / -2.",
"deviations": [
"The claim's file surface reads 'the modalSizeClasses map only'. The ruling's one value lives in a module constant declared directly above the map, which the lg and xl rows read. It is still ModalForm.tsx, with no other symbol touched.",
"A3 was measured false. The 12521 pins were not edited, because they still pass with their meaning intact. Rewriting them would only be needed for a min(...) max-width shape, which writes the 2rem literal once per size and so breaks the one-value ruling.",
"A shell backgrounding mistake wrote a 5-byte pid file at the container root, /build.pid. The variable naming my scratchpad was unset in the parent shell. It holds the pid of a finished build. The harness safety check refused my rm of it, so it is still there. It is outside every repository and has no effect on the work."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: named producer, objectstack examples/app-showcase showcase_quick_view (type 'modal', target page showcase_component_gallery, no size). The console's modal action path, app-shell useActionModal resolveModalTarget, gives such a page target size 'xl' · evidence: useActionModal's SIZE_CLASS maps xl → 'sm:max-w-5xl' and lg → 'sm:max-w-2xl' onto the Shadcn DialogContent primitive's 'w-full max-w-lg'. The same Chromium harness over the console's emitted CSS measured 1440 → 1024 · 208/208, 1024 → 1024 · 0/0 and 768 → 768 · 0/0 (width · left/right gutter, px). It is the same edge-to-edge defect, in a dialog this dispatch keeps off the PR. Not filed, not fixed · dedupe words: 'useActionModal SIZE_CLASS edge to edge', 'action modal xl viewport margin', 'DialogContent sm:max-w-5xl w-full gutter'",
"carrier: none (承接者:无) · noted, not filed: the dialog-size paragraph in content/docs/plugins/plugin-form.mdx states no widths, so nothing in it becomes false. No docs edit was made."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed ·
domain:uiseat 1 ·session_01JZnppgHRp4sREcouhkQYDB· 2026-10-16T03:18Zmain85e8961f28at 2026-10-16T03:17Z. It has one parent,8415d9f111, and is an ancestor oforigin/main.85e8961f28to the accepted headc57843d95d.8719bd944c81).Fixes #12593. The only issue closed with this merge is this card, ascompleted.sm(640 px) up, anlgorxlModalFormdialog keeps a 1rem gutter on each side of the window, under its own max width. Measured forxl: 992 px with 16/16 gutters at 1024, and 736 px with 16/16 at 768. It is still 1024 px at 1440.sm,default,full, the phone sheet and the height rules are unchanged.finding) covers the same edge-to-edge defect in the action modal and six more wide dialogs, outsideModalForm.6206287250, claim6206600248, dev report6206971611, ACCEPT6207100306.Generated by Claude Code