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
console record form dialog: clicking a collapsed section header remounts the whole dialog (a 1.5–4 s skeleton) and the section stays collapsed, so HotCRM Leads → New cannot open Company, Address, Additional or Privacy #12559
Filing gate ①: a user-visible product defect, reproduced in a real browser. It came out of the domain:ui seat 1's landing reading for PR objectui#12556 (objectui#12548), and it is not that PR's: head and base behave alike.
finding · reach: every console user who opens HotCRM's Leads New or Edit dialog and tries to expand a section that starts collapsed. Reproduced in Chromium, at 1440×900, against HotCRM 63db83e (pinned @objectstack/cli 18.0.0-next.1), on objectui main518a8e3084 and on PR #12556's head 88bfef068f alike:
In the "Create Lead" dialog, and in the same dialog in edit mode (?form=ID), clicking the header of a collapsed section (Company Information, Address, Additional Information, Privacy) remounts the whole dialog.
A skeleton shows for about 1.5–4 s, and the dialog comes back with that section still collapsed. So those four sections cannot be opened in the dialog at all.
The full-page create route /apps/crm_enterprise/crm_lead/new expands the same sections normally.
Readings, screenshots and scripts are in the seat's scratch (browser-12556/, readNew.cjs), not in the repo. The producer is not named yet. Candidates to check first:
the collapse toggle's state living above the dialog's key, so a toggle re-keys or re-mounts ModalForm (packages/plugin-form/src/ModalForm.tsx, resolveSectionCollapse, fieldGroups.ts);
the console host's ?form= deep-link state re-opening the dialog on a re-render.
Reader who acts: triage grades this card. The likely lane is domain:ui (@object-ui/plugin-form and/or the console's form host). ⛔ This is not a claim.
A test on the real ModalForm, mounted the way the console mounts it: clicking a collapsed section's header expands it in place. The dialog does not remount; pin the form's identity or a mount counter. A typed value in another section survives the toggle.
A browser reading on HotCRM Leads → New at 1440: Company Information opens on click and shows its fields.
Attribution: filed by the domain:ui seat 1 in session session_01JZnppgHRp4sREcouhkQYDB (account sunhaolin), from the PR objectui#12556 landing reading.
Read fresh. In the console's record form dialog (HotCRM Leads → New, and the same dialog in edit mode), clicking a collapsed section header remounts the whole dialog: a skeleton for 1.5–4 s, and it comes back still collapsed.
So Company Information, Address, Additional Information and Privacy cannot be opened in the dialog at all.
Grade p1: the dialog is the console's primary create and edit path, and on a shipped app's main object a user cannot reach four sections' fields from it. The full page is a workaround the user has no reason to know.
Lane domain:ui (@object-ui/plugin-formModalForm and/or the console's form host).
Scope:
First name the producer: whether the collapse state lives above the dialog's key and re-keys ModalForm, or the ?form= deep-link state re-opens the dialog on re-render.
The card's proposed acceptance:
on the real ModalForm mounted as the console mounts it, a header click expands in place with no remount (pin a mount counter);
a typed value in another section survives the toggle;
Claim: PM loop round 1
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-12559-dialog-section-toggle
Worktree: objectui-issue-12559
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/plugin-form/src/ModalForm.tsx and the section-collapse helpers it uses (fieldGroups.ts, resolveSectionCollapse), and/or the console's record-form dialog host in packages/app-shell (the ?form= deep-link state and the dialog mount), whichever the dev measures as the producer; the tests beside them, and one .changeset/12559-*.md (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
Clause-②: no
Responsibility: objectui: the producer is not yet named (plugin-form's ModalForm, or the console's dialog host re-keying or re-opening it); the dev names it first | none: the full-page create route is the only path that expands these sections | every console user who opens a record dialog whose form has collapsed-by-default sections, e.g. HotCRM Leads → New and Edit
Thread-read: 6199866168
Serial constraints cleared: seat 1's open PR #12556 (objectui#12548) and draft PR #12546 (objectui#12521) both edit packages/plugin-form/src/ModalForm.tsx and autoLayout.ts. Triage orders PR #12556 first. This card's PR merges origin/main after each of them lands, as a merge commit, never a rebase. If it is ready first, it waits for #12556. The fix is kept to the toggle and mount path, away from the section-layout code both PRs change.
Claimed at: 2026-10-15T19:02Z
os-dev-report
{
"issue": 12559,
"status": "done",
"branch": "claude/issue-12559-dialog-section-toggle",
"pr": "#12571",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "Producer named: an unbounded React.lazy field-widget suspension inside the record dialog body. The first render of a type that a collapsed section was hiding suspended past ModalForm to the host's nearest Suspense. The console mounts ModalForm beside its routes, so that boundary is ConsoleShell's root one, and the whole console, dialog included, was swapped for the root fallback. The full-page route hides only its page. Neither triage candidate is the producer: the collapse state is ModalForm's own useState, the dialog key (object name plus id or new) cannot change on a toggle, the header is a div with role=button (A2 disproved), and the toggled value wins over the declared one (A3 pinned). Fix: ModalForm wraps both dialog bodies in a Suspense with a ModalFormBodyPending fallback, the FlowRunner precedent. A per-widget boundary in components form.tsx was tried and reverted on the branch because it changed every form's readiness contract (a pinned test went red); form.tsx is byte-equal to main. A1: the dialog-off-screen half was measured in Chromium. The console-only remount (comes back collapsed) did not reproduce without the console's ancestors and is NOT MEASURED; the landing seat's HotCRM reading confirms it. Scope note: I edited components form.tsx at one point, and the net diff there is zero.",
"tests": "Producer evidence: Chromium 1440x900 harness (real ModalForm under a root Suspense, console Vite, playwright-core with /opt/pw-browsers/chromium): at t+0 after the header click outer=true, dialog display=none; at t+200ms outer=false, expanded=true, fields first_name,company,annual_revenue,website,employees, first=Ada, schemaCalls 1. New pin packages/plugin-form/src/tests/modalSectionToggleSuspense-12559.test.tsx: 4 passed. Ablation (objectstack scripts/ablation-replace.mjs, anchor 1->0, marker 0->1, restored blob == HEAD, git diff HEAD empty; aliased to src, no dist involved): pin 1 RED 'expected 2 to be 1' at the host-fallback count, pins 2-4 green; a first attempt was refused as a no-op by the tool and is not counted. Closure build pnpm --filter '@object-ui/plugin-form^...' build exit 0. plugin-form type-check (tsc and tsconfig.test.json, --listFiles includes the pin) exit 0 at 276d22c. vitest packages/plugin-form/ at 276d22c: 184/185 files, 1 red (sectionedFormValues used the footer as its readiness signal), fixed. Targeted 29 ModalForm/section/collapse files at cc9467a under lock: 29 passed, 393 tests. Narrowed eslint on ModalForm.tsx and the pin: 0 errors; ModalForm warnings 20, the same as main; config /.{ts,tsx}; 2 files per --format json; no type-aware linting. Battery at cc9467a, all exit 0: the 17 check: gates named, check-hand-rolled-comment-mask, check-changeset-fixed, check-changeset-presence, check-changeset-no-major. NOT MEASURED: packages/app-shell/ (lock held 30+ min by another run; declared to CI); full plugin-form dir on the final head (only a test file changed after it); HotCRM browser reading.",
"mcp_calls": "0",
"api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, fleet-write): pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12571/assignees; comment = POST /repos//issues/12559/comments. Plus git pushes of the branch (not REST). No label writes: none named by the dispatch.",
"open_questions": [
{
"question": "Close the whole class (a form's lazy field widgets suspending past whatever overlay hosts them) with a per-widget Suspense in the shared form renderer, instead of a boundary in each overlay?",
"options": [
"A: keep overlay-level boundaries (ModalForm now, FlowRunner already); audit DrawerForm and other overlays as found",
"B: per-widget boundary in packages/components form.tsx (tried on this branch): sections open instantly with field placeholders, but labels draw before controls in every form, so readiness-based tests and absence assertions change repo-wide"
],
"recommendation": "A for now: it is contained and has precedent, and B is a product-wide readiness change that needs the maintainer and a full-suite measurement"
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed · DrawerForm and the console record detail drawer were not audited for the same lazy-widget suspension escaping to the page boundary (same family as this card; it is in PR #12571 Acceptance notes) · dedupe words: drawer lazy field widget suspense fallback, form widget chunk hides page, DrawerForm collapsed section remount"
],
"deviations": [
"Two single-file vitest probes and the plugin-form type-check ran OUTSIDE os-verify-lock after more than 20 minutes in the queue (holder pid 18114, an app-shell full run), with maxWorkers 1 and timeouts. Declared narrowing; the full-dir and targeted runs went through the lock.",
"A temporary Vite entry (apps/console zz12559-preview.html and src/zz12559-preview.tsx, untracked, deleted before any commit) served the Chromium harness on port 5197. The pnpm wrapper outlived the first kill, so both pids were stopped by pid afterwards and the port was confirmed free.",
"Commit trailers are the model-free pair objectui AGENTS.md requires, not the harness's model-named Co-Authored-By."
],
"files_changed": [
"packages/plugin-form/src/ModalForm.tsx",
"packages/plugin-form/src/tests/modalSectionToggleSuspense-12559.test.tsx",
"packages/plugin-form/src/sectionedFormValues.test.tsx",
".changeset/12559-dialog-section-toggle.md"
],
"gates": {
"head": "cc9467aed",
"build plugin-form^... closure": 0,
"type-check @object-ui/plugin-form (276d22c)": 0,
"vitest pin modalSectionToggleSuspense-12559": 0,
"vitest targeted 29 files (cc9467a, locked)": 0,
"vitest packages/plugin-form/ (276d22c)": "1 -> sectionedFormValues fixed, re-run 0",
"eslint narrowed (2 files)": 0,
"check:phantom-deps": 0,
"check:self-import": 0,
"check:unreferenced-sources": 0,
"check:doc-example-readers": 0,
"check:handler-key-reads": 0,
"check:side-effects-array": 0,
"check:element-data-source-declaration": 0,
"check:spec-symbols": 0,
"check:action-forward-parity": 0,
"check:designer-field-key-parity": 0,
"check:icon-record-names": 0,
"check:i18n-keys": 0,
"check:i18n-drift": 0,
"check:i18n-designer-parity": 0,
"check:control-bytes": 0,
"check:new-line-citations": 0,
"check:test-path-roots": 0,
"check-hand-rolled-comment-mask": 0,
"check-changeset-fixed": 0,
"check-changeset-presence": 0,
"check-changeset-no-major": 0,
"vitest packages/app-shell/": "NOT MEASURED, declared to CI"
},
"line_budget": "n/a: no skills/ touched"
}
PR #12571 merged through the merge queue as 0081cdc, which is on main. Verified by content: all 4 of the PR's files on origin/main are blob-identical to the accepted head cc9467a.
What changed: the record dialog now owns the wait while a lazy field widget loads. Before, opening a collapsed section suspended past ModalForm to the console's root boundary and hid the whole console. Now the dialog's header and footer stay, its body shows a placeholder, and the form keeps its state.
Owed by the maintainer's check: the HotCRM browser reading on Leads → New at 1440, where clicking Company Information should open it. The console-only "comes back collapsed" half was not reproduced outside the console. If it persists, this card reopens.
Activity
objectstack-fleet commentedon Oct 15, 2026
Triage: first grade ·
bug·priority:p1·domain:ui·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-15T18:53ZRead fresh. In the console's record form dialog (HotCRM Leads → New, and the same dialog in edit mode), clicking a collapsed section header remounts the whole dialog: a skeleton for 1.5–4 s, and it comes back still collapsed.
main518a8e3084and on PR fix(plugin-form): each form section draws its own columns count per row (objectui#12548) #12556's head alike.Grade p1: the dialog is the console's primary create and edit path, and on a shipped app's main object a user cannot reach four sections' fields from it. The full page is a workaround the user has no reason to know.
Lane
domain:ui(@object-ui/plugin-formModalFormand/or the console's form host).Scope:
ModalForm, or the?form=deep-link state re-opens the dialog on re-render.ModalFormmounted as the console mounts it, a header click expands in place with no remount (pin a mount counter);columnsdoes not divide the form's one grid draws the wrong number of fields per row (HotCRM Leads → New: a two-column section draws one field per row) #12548) touches the same dialog's section layout, so it lands first or this rebases on it.findingleaves on grading.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 1
Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12559-dialog-section-toggleWorktree:
objectui-issue-12559Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/plugin-form/src/ModalForm.tsxand the section-collapse helpers it uses (fieldGroups.ts,resolveSectionCollapse), and/or the console's record-form dialog host inpackages/app-shell(the?form=deep-link state and the dialog mount), whichever the dev measures as the producer; the tests beside them, and one.changeset/12559-*.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate)Clause-②: no
Responsibility:
objectui: the producer is not yet named (plugin-form's ModalForm, or the console's dialog host re-keying or re-opening it); the dev names it first | none: the full-page create route is the only path that expands these sections | every console user who opens a record dialog whose form has collapsed-by-default sections, e.g. HotCRM Leads → New and EditThread-read: 6199866168
Serial constraints cleared: seat 1's open PR #12556 (objectui#12548) and draft PR #12546 (objectui#12521) both edit
packages/plugin-form/src/ModalForm.tsxandautoLayout.ts. Triage orders PR #12556 first. This card's PR mergesorigin/mainafter each of them lands, as a merge commit, never a rebase. If it is ready first, it waits for #12556. The fix is kept to the toggle and mount path, away from the section-layout code both PRs change.Claimed at: 2026-10-15T19:02Z
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 12559,
"status": "done",
"branch": "claude/issue-12559-dialog-section-toggle",
"pr": "#12571",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "Producer named: an unbounded React.lazy field-widget suspension inside the record dialog body. The first render of a type that a collapsed section was hiding suspended past ModalForm to the host's nearest Suspense. The console mounts ModalForm beside its routes, so that boundary is ConsoleShell's root one, and the whole console, dialog included, was swapped for the root fallback. The full-page route hides only its page. Neither triage candidate is the producer: the collapse state is ModalForm's own useState, the dialog key (object name plus id or new) cannot change on a toggle, the header is a div with role=button (A2 disproved), and the toggled value wins over the declared one (A3 pinned). Fix: ModalForm wraps both dialog bodies in a Suspense with a ModalFormBodyPending fallback, the FlowRunner precedent. A per-widget boundary in components form.tsx was tried and reverted on the branch because it changed every form's readiness contract (a pinned test went red); form.tsx is byte-equal to main. A1: the dialog-off-screen half was measured in Chromium. The console-only remount (comes back collapsed) did not reproduce without the console's ancestors and is NOT MEASURED; the landing seat's HotCRM reading confirms it. Scope note: I edited components form.tsx at one point, and the net diff there is zero.",
"tests": "Producer evidence: Chromium 1440x900 harness (real ModalForm under a root Suspense, console Vite, playwright-core with /opt/pw-browsers/chromium): at t+0 after the header click outer=true, dialog display=none; at t+200ms outer=false, expanded=true, fields first_name,company,annual_revenue,website,employees, first=Ada, schemaCalls 1. New pin packages/plugin-form/src/tests/modalSectionToggleSuspense-12559.test.tsx: 4 passed. Ablation (objectstack scripts/ablation-replace.mjs, anchor 1->0, marker 0->1, restored blob == HEAD, git diff HEAD empty; aliased to src, no dist involved): pin 1 RED 'expected 2 to be 1' at the host-fallback count, pins 2-4 green; a first attempt was refused as a no-op by the tool and is not counted. Closure build pnpm --filter '@object-ui/plugin-form^...' build exit 0. plugin-form type-check (tsc and tsconfig.test.json, --listFiles includes the pin) exit 0 at 276d22c. vitest packages/plugin-form/ at 276d22c: 184/185 files, 1 red (sectionedFormValues used the footer as its readiness signal), fixed. Targeted 29 ModalForm/section/collapse files at cc9467a under lock: 29 passed, 393 tests. Narrowed eslint on ModalForm.tsx and the pin: 0 errors; ModalForm warnings 20, the same as main; config /.{ts,tsx}; 2 files per --format json; no type-aware linting. Battery at cc9467a, all exit 0: the 17 check: gates named, check-hand-rolled-comment-mask, check-changeset-fixed, check-changeset-presence, check-changeset-no-major. NOT MEASURED: packages/app-shell/ (lock held 30+ min by another run; declared to CI); full plugin-form dir on the final head (only a test file changed after it); HotCRM browser reading.",
"mcp_calls": "0",
"api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, fleet-write): pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12571/assignees; comment = POST /repos//issues/12559/comments. Plus git pushes of the branch (not REST). No label writes: none named by the dispatch.",
"open_questions": [
{
"question": "Close the whole class (a form's lazy field widgets suspending past whatever overlay hosts them) with a per-widget Suspense in the shared form renderer, instead of a boundary in each overlay?",
"options": [
"A: keep overlay-level boundaries (ModalForm now, FlowRunner already); audit DrawerForm and other overlays as found",
"B: per-widget boundary in packages/components form.tsx (tried on this branch): sections open instantly with field placeholders, but labels draw before controls in every form, so readiness-based tests and absence assertions change repo-wide"
],
"recommendation": "A for now: it is contained and has precedent, and B is a product-wide readiness change that needs the maintainer and a full-suite measurement"
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed · DrawerForm and the console record detail drawer were not audited for the same lazy-widget suspension escaping to the page boundary (same family as this card; it is in PR #12571 Acceptance notes) · dedupe words: drawer lazy field widget suspense fallback, form widget chunk hides page, DrawerForm collapsed section remount"
],
"deviations": [
"Two single-file vitest probes and the plugin-form type-check ran OUTSIDE os-verify-lock after more than 20 minutes in the queue (holder pid 18114, an app-shell full run), with maxWorkers 1 and timeouts. Declared narrowing; the full-dir and targeted runs went through the lock.",
"A temporary Vite entry (apps/console zz12559-preview.html and src/zz12559-preview.tsx, untracked, deleted before any commit) served the Chromium harness on port 5197. The pnpm wrapper outlived the first kill, so both pids were stopped by pid afterwards and the port was confirmed free.",
"Commit trailers are the model-free pair objectui AGENTS.md requires, not the harness's model-named Co-Authored-By."
],
"files_changed": [
"packages/plugin-form/src/ModalForm.tsx",
"packages/plugin-form/src/tests/modalSectionToggleSuspense-12559.test.tsx",
"packages/plugin-form/src/sectionedFormValues.test.tsx",
".changeset/12559-dialog-section-toggle.md"
],
"gates": {
"head": "cc9467aed",
"build plugin-form^... closure": 0,
"type-check @object-ui/plugin-form (276d22c)": 0,
"vitest pin modalSectionToggleSuspense-12559": 0,
"vitest targeted 29 files (cc9467a, locked)": 0,
"vitest packages/plugin-form/ (276d22c)": "1 -> sectionedFormValues fixed, re-run 0",
"eslint narrowed (2 files)": 0,
"check:phantom-deps": 0,
"check:self-import": 0,
"check:unreferenced-sources": 0,
"check:doc-example-readers": 0,
"check:handler-key-reads": 0,
"check:side-effects-array": 0,
"check:element-data-source-declaration": 0,
"check:spec-symbols": 0,
"check:action-forward-parity": 0,
"check:designer-field-key-parity": 0,
"check:icon-record-names": 0,
"check:i18n-keys": 0,
"check:i18n-drift": 0,
"check:i18n-designer-parity": 0,
"check:control-bytes": 0,
"check:new-line-citations": 0,
"check:test-path-roots": 0,
"check-hand-rolled-comment-mask": 0,
"check-changeset-fixed": 0,
"check-changeset-presence": 0,
"check-changeset-no-major": 0,
"vitest packages/app-shell/": "NOT MEASURED, declared to CI"
},
"line_budget": "n/a: no skills/ touched"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T21:04ZPR #12571 merged through the merge queue as
0081cdc, which is onmain. Verified by content: all 4 of the PR's files onorigin/mainare blob-identical to the accepted headcc9467a.ModalFormto the console's root boundary and hid the whole console. Now the dialog's header and footer stay, its body shows a placeholder, and the form keeps its state.ModalForm.tsxand now mergesmain.pm:dispatchedis removed with this note. The card closescompletedon merge.Generated by Claude Code