Repository navigation
plugin-form: the tabbed Edit/New form dialog renders no tab for a { group } form section, so group-referenced fields have no editing surface there (moved from objectstack-ai/objectstack#21543, item 1) #11542
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchand removed
on Oct 3, 2026 objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsClaim: PM loop round 1
Session:session_01FjqrwXPfSMkSfkKYDSRkN2
Account:os-zhuang(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-11542-modal-form-group-sections
Worktree:objectui-issue-11542
Domain:domain:ui
Seat:domain:ui#1
File surface: the measurement the card asks for, read by this seat at objectuiorigin/main6f5719e1c, is a lead for the dev and not an answer. The More actions › Edit / New dialog rendersModalFormdirectly, frompackages/app-shell/src/console/AppContent.tsxandpackages/app-shell/src/hooks/useActionModal.tsx.packages/plugin-form/src/ModalForm.tsxtakesschema.sectionsas given and never callsresolveSectionGroupReferences(0 hits inModalForm.tsx,DrawerForm.tsx,TabbedForm.tsx,WizardForm.tsx,SplitForm.tsx; control:ObjectForm.tsxcalls it atwithGroups). So the expected landing is:packages/plugin-form/src/ModalForm.tsx: resolve{ group }sections through the one resolver before its sections reach either content layout;packages/plugin-form/src/DrawerForm.tsx: only if the dev measures a host that renders it directly with authored sections (same ruling: every form surface);- tests under
packages/plugin-form/src/__tests__/; - one changeset for
@object-ui/plugin-form.
⛔ Not
packages/app-shell/**. ⛔ Not the assembly rules insectionGroups.ts. The dev stops on a breach and explains it in the report.
Container & model:M,mode:subagent,model: opus(default judgment tier;dispatch-gates --tier --repo objectstack-ai/objectuiprinted "no path-derived mandate" forModalForm.tsxandDrawerForm.tsx)
Clause-②: no
Why no: the dialog starts rendering sections the spec already accepts (the{ group }form of objectstack#13855). No accept set moves, and no published input or type is added.
Thread-read: none
Serial constraints cleared: read 2026-10-03T12:35Z.- The 17.6 trunk objectui#11531 (81 files): its only
plugin-formchange is a one-line comment restamp atformSectionGroupReference-7051.test.tsx:451. If the dev edits that file, it leaves that line alone. - The director's in-flight branches (objectui#11344 action surfaces, finding(types,plugin-grid): eight declared ObjectGridSchema keys have no read in ObjectGrid, and the schema reference teaches two of them #11068 grid keyboard, finding(fields,app-shell,spec): 「is empty」 has three meanings across objectui and the spec ($null only, $exists, or "null OR empty string"), and the empty-string member may not reach typed SQL columns safely #10813 filter builders) touch no
plugin-formfile. - Open PRs: objectui#11512 touches
plugin-form/src/MasterDetailForm.i18nLabels.test.tsxonly, and objectui#11069 nothing here. Both are disjoint. - Batch siblings: objectui#9600 (
plugin-gridImportWizard.tsx) and objectui#11539 (app-shellMetadataProvider.tsx) are disjoint by file.⚠️ objectui#11539 is semantically adjacent: it changes WHICH form view feeds this dialog's.form, and this card changes how the dialog renders that view's sections.
Generated by Claude Code
objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 11542, "status": "done", "branch": "claude/issue-11542-modal-form-group-sections", "pr": "https://github.com/objectstack-ai/objectui/pull/11551", "session": "session_01FjqrwXPfSMkSfkKYDSRkN2 (mode:subagent run of the PM session; identity = the claim branch)", "premise_still_valid": true, "summary": "Measured answer to the card's question: a branch before withGroups, one level above ObjectForm. AppContent and useActionModal mount ModalForm directly, spreading resolveFormViewLayout's as-authored formView.sections, so neither withGroups nor canResolveGroups runs. A { group } section reached ModalForm with no fields, built an empty body and was dropped by the empty-body filter above the layout fork, in both the tabbed and the stacked layout, and in create and edit alike. ModalForm now resolves its sections once through resolveSectionGroupReferences, with ObjectForm's four inputs and the objectSchema it already loads; the call returns its input by identity when no section uses group. Resolved members pass the dialog's one field gate (gateFields). Landing is packages/plugin-form/src/ModalForm.tsx plus a new pin file, one plugin-form patch changeset and one README paragraph. DrawerForm is unchanged: its only direct host, FieldDesigner, builds its sections in code. The master-detail modal arm already resolved through ObjectForm (throwaway probe, not committed). The branch was merged with origin/main 6158e4c (17.6.0 trunk) as the PM instructed, and all gates were re-run on the merged head 202a8c0.", "tests": "RED before any source edit (origin/main 6f5719e1c), new pin modalFormSectionGroupReference-11542.test.tsx: 9 failed | 2 passed (11); the 2 passing legs are the hand-enumerated control; the tabbed leg read [identity, contact_info] where [identity, contact_info, buying_centre] was expected. GREEN after the fix: 11 passed (11). REVERSE VERIFICATION from committed state (e7e7413 lineage): ModalForm.tsx restored to its 6f5719e1c blob under a trap on EXIT, INT and TERM; on-disk proof: marker resolveSectionGroupReferences count 2 to 0, on-disk hash = base blob 146186f; pin 9 failed | 2 passed; restored with git checkout HEAD -- PATH, on-disk hash = HEAD blob, marker back to 2, git diff HEAD = 0 bytes, status clean. No dist leg: the test imports ../ModalForm from src, and vitest.config.mts aliases @object-ui/plugin-form to src. MERGED HEAD 202a8c0: plugin-form^... build exit 0 (Scope 12 of 47); pnpm --filter @object-ui/plugin-form test exit 0, Test Files 162 passed (162), Tests 1859 passed | 1 skipped (1860), and 162 = HEAD test-file count, 161 at base; type-check exit 0, script echoed as tsc --noEmit && tsc -p tsconfig.test.json, and --listFilesOnly lists the new file; eslint . over plugin-form exit 0, 202 files in --format json, 0 errors, ModalForm.tsx 20 warnings = base blob 20; 11 app-shell/console test files rendering the real ModalForm exit 0, 137 passed.", "mcp_calls": "0", "api_writes": "2 attempted REST writes through scripts/pm (relay). 1 landed: pr_create, a repository_dispatch to objectstack-ai/objectstack executing POST /repos/objectstack-ai/objectui/pulls (draft forced) as PR 11551, read-back 9717 bytes sent = 9717 stored, identical. 1 refused before sending: label-write --assign os-zhuang on PR 11551, denied by the auto-mode classifier (External System Writes), so 0 requests went out. 1 more = this os-dev-report comment via post-stamped.mjs --comment=11542 (POST /repos/objectstack-ai/objectui/issues/11542/comments). git push is not counted: 5 pushes of the branch.", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted in the PR's Acceptance notes, not filed · DrawerForm mounted directly does not resolve { group } sections. No reach: its only direct host (FieldDesigner, plugin-designer) builds sections in code with fields, and ObjectForm's formType drawer route resolves above its fork. Dedupe words: DrawerForm group section direct mount resolveSectionGroupReferences" ], "gates": [ { "command": "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-form^...' build", "exit": 0, "verdict": "Scope: 12 of 47 workspace projects; os-verify-lock VERDICT command-exit 0 (merged head 202a8c0)" }, { "command": "pnpm --filter @object-ui/plugin-form test", "exit": 0, "verdict": "Test Files 162 passed (162); Tests 1859 passed | 1 skipped (1860) at 202a8c0" }, { "command": "pnpm --filter @object-ui/plugin-form type-check", "exit": 0, "verdict": "tsc --noEmit && tsc -p tsconfig.test.json, exit 0 at 202a8c0" }, { "command": "cd packages/plugin-form && npx eslint . --format json", "exit": 0, "verdict": "202 files, 0 errors; ModalForm.tsx warnings 20 = base 20 (no --max-warnings in this repo)" }, { "command": "pnpm exec vitest run (11 app-shell/console files that render ModalForm)", "exit": 0, "verdict": "Test Files 11 passed (11), Tests 137 passed (137) at 202a8c0" }, { "command": "pnpm check:control-bytes", "exit": 0, "verdict": "check-control-bytes: OK" }, { "command": "pnpm check:new-line-citations", "exit": 0, "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)" }, { "command": "pnpm check:changeset-claims", "exit": 0, "verdict": "No pending changeset names a file this change touches" }, { "command": "pnpm check:pending-changeset-literals", "exit": 0, "verdict": "No test source names a pending changeset" }, { "command": "node scripts/check-changeset-presence.mjs", "exit": 0, "verdict": "2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)" }, { "command": "node scripts/check-changeset-no-major.mjs / -overwrite.mjs / -fixed.mjs", "exit": 0, "verdict": "no major; no pre-existing changeset modified; privatePackages declared" }, { "command": "node scripts/check-test-path-roots.mjs", "exit": 0, "verdict": "check-test-path-roots: OK" }, { "command": "node scripts/check-type-check-coverage.mjs", "exit": 0, "verdict": "43/43 packages compile their tests" }, { "command": "pnpm check:unreferenced-sources", "exit": 0, "verdict": "Every shipped source file in every covered package is reachable" }, { "command": "node scripts/check-doc-links.mjs", "exit": 0, "verdict": "Links are valid across 17 scan roots" }, { "command": "pnpm check:readme-exports", "exit": 1, "verdict": "NOT MEASURED: PREREQUISITE NOT MET, population COLLAPSED (25 packages unbuilt); CI lane. The README edit is prose only, with no fenced block or import binding, which is what the gate judges" } ], "files_changed": [ "packages/plugin-form/src/ModalForm.tsx", "packages/plugin-form/src/__tests__/modalFormSectionGroupReference-11542.test.tsx", ".changeset/modal-form-section-group-11542.md", "packages/plugin-form/README.md" ], "deviations": [ "PR assignee NOT set: `node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 11551 --assign os-zhuang` (run from /home/user/objectstack) was denied by the auto-mode classifier [External System Writes]. Not retried by another route. Seat to apply.", "README paragraph added beyond the claim's expected landing list (AGENTS.md commandment #2, docs-driven). It states that ModalForm resolves its own sections and that a directly mounted DrawerForm does not.", "Stopped my own queued pre-merge verification run (TaskStop; it had not acquired the lock) when the PM's merge instruction arrived, then re-ran everything on the merged head 202a8c0.", "Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) rather than the harness reminder's model-named Co-Authored-By, per the precedence the reminder itself states. The merge commit was amended locally to carry the pair before its first push.", "One verify-lock queue-timeout (exit 99, NOT MEASURED) on an early whole-package lint attempt; superseded by the lint run on 202a8c0.", "Worktree /home/user/objectui-issue-11542 removed after the PR opened (node_modules deleted first; local HEAD = remote branch 202a8c0 verified before removal)." ], "line_budget": "n/a (no skills/** touched)", "clause_2": "Clause-② line copied at line start into the PR body: no" }
Generated by Claude Code
objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actions✅ ACCEPT: PR objectui#11551 at head
202a8c0eb(dev reportos-dev-reporton this card)domain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-03T13:45Z. Reviewed against GitHub, not the report.- Shape: draft, base
main. The first line isFixes #11542and no other closing keyword appears in the body.Clause-②: nois at line start.- 4 files, +366 / −5:
ModalForm.tsx, one new pin file, one@object-ui/plugin-formpatch changeset and one README paragraph. - Inside the claim's surface, plus the README paragraph (docs-driven, accepted).
- No governed path, no
content/docs/releases/.
- 4 files, +366 / −5:
- The card's question, answered: a branch before
withGroups.AppContentanduseActionModalmountModalFormdirectly with the form view's sections as authored, so a{ group }section arrived with no fields and was dropped above the layout fork. That held in both layouts, for create and edit alike. - The diff, read:
ModalFormresolves once throughresolveSectionGroupReferenceswithObjectForm's four inputs against theobjectSchemait already loads.- The tabbed/stacked render path now reads
resolvedSections. - The call returns its input by identity when no section uses
group, so every other modal keeps its path. - The remaining
schema.sectionsreads at the head (:362the field-group fallback guard,:571the flat-field effect's early return,:1062the master-detail hand-off) are section-presence checks or hand-offs toObjectForm. None draws a section, so none needs the resolved list.
- The tabbed/stacked render path now reads
- Pins (
modalFormSectionGroupReference-11542.test.tsx):- the group's tab with exactly its members;
- the hand-enumerated control;
- an edit carrying record values and a create payload holding a value typed on the group tab;
- the stacked layout;
- FLS on a group member;
- an unknown group reported once.
- Red before the fix (9 failed / 2 passed; the 2 passing are the control), green after (11/11), reverse-verified with a hash-proven restore.
- Changeset prose, checked sentence by sentence against the diff: "resolves its sections through
resolveSectionGroupReferences, the same resolverObjectFormuses, against the object schema it already loads" ✓ · "its members pass the same field-level security gate" ✓ (FLS pin) · "an unknown group renders nothing and is reported once" ✓ (pin) · "A section list that uses nogroupreaches the dialog unchanged" ✓ (identity return). - Deviations:
- The PR assignee is not set; the dev's write was refused in its own context. It is left to the maintainer, ⛔ not re-run by this seat on the dev's behalf.
check:readme-exportsis NOT MEASURED locally (25 unbuilt packages); CI'sREADME Export Checkjudges it.
- Out-of-scope: directly mounted
DrawerFormdoes not resolve{ group }. No reach is measured (its one direct host builds its sections in code), so it goes in Acceptance notes and is ⛔ not filed. - Landing: when every check on
202a8c0ebis green, the seat lands it through the merge queue (pr_ready+automerge_enable).
Generated by Claude Code
- Shape: draft, base
objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsLanded and verified by content: closed
completedby PR objectui#11551 ·domain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-03T14:24Z.-
The merge: PR objectui#11551 went through the merge queue to
mainas584eecae8at 2026-10-03T14:17Z. -
Content check on
main584eecae8against its first parent9bfd0b36e:mainparent resolveSectionGroupReferencesinpackages/plugin-form/src/ModalForm.tsx2 0 the control export const ModalForm1 1 modalFormSectionGroupReference-11542.test.tsxin the treepresent absent -
Cards closed in that window: this one and objectui#11539 (this seat's, via PR objectui#11549), plus objectui#11344 (the director's). None closed by mistake.
-
pm:dispatchedis removed in the same act.domain:ui,area:records, the type and the priority stay.
Generated by Claude Code
-
- added a commit that references this issue
on Oct 3, 2026
Filed by the triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015,
session_01AavokzJ5DndAwitDXvKy4U). It moves item 1 of objectstack-ai/objectstack#21543 here, where the fix lands. That card was filed by therepo:hotcrmseat (session_01ER8ntXZhYebyQ66aXWdjfT) from a measured run. ⛔ Not a claim, ⛔ not a dispatch.Graded here:
bug·priority:p1·domain:ui·area:records·pm:queue.Measured (hotcrm on
@objectstack/*17.6.0, Chromium; the served metadata was checked equal to the compiled artifact)src/sales/views/contact.view.tsdeclaresform.sectionswith a{ group: 'buying_centre', columns: 2 }section, the group-reference form of objectstack#13855.{ group }sections render no tab, while its hand-enumerated sections do.record:detailson the same records renders the same{ group }references, so the spec form is served and only the form dialog drops it.Why p1
A shipped app's create and edit dialog silently loses whole sections, and the fields only those sections carry cannot be edited there. It is the same class as objectstack-ai/objectstack#21500 (p1).
Where (read at
origin/main160c6c6eaf)completed, PR fix(plugin-form,types): resolveform.sections[].groupthrough the single field-group assembler, and bound the section loop that blanked the form #8644) delivered the group-reference reading forrecord:detailsand for viewform.sections.packages/plugin-form/src/ObjectForm.tsxresolves{ group }sections throughresolveSectionGroupReferences(withGroups), gated bycanResolveGroups.apps/console/src/components/FormPage.tsxand the metadata-adminSchemaFormcall the same resolver.withGroupsor the gate answering false there, and states which.Ruling
{ group }sections through the one resolver,resolveSectionGroupReferences, which derives fromderiveFieldGroupLayout. The fix goes at the shared seam the dialog reaches.{ group }section, which shows that group's tab in the Edit and New dialog;Related
record:detailsedit mode offers no markdown editor. Together the two leave some fields with no editing surface at all.Dedupe: MCP
search_issues, repo-scoped, for 「tabbed form dialog group section tab missing form.sections group reference」 → 6 hits, all closed and none this dialog: objectui#8725, #2959, #8641 (FormPage), #8278, #7051 and #4774 (DrawerForm).