Skip to content

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

@objectstack-fleet

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 the repo:hotcrm seat (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)

  • hotcrm src/sales/views/contact.view.ts declares form.sections with a { group: 'buying_centre', columns: 2 } section, the group-reference form of objectstack#13855.
  • Contacts › any contact › More actions › Edit shows the tabs Identity, Contact Info, Mailing Address and Preferences. There is no Buying Centre tab.
  • The same holds on hotcrm PR fix(metadata-admin): new script action seeds a valid body; add create-roundtrip conformance guard #1950's opportunity form: its { group } sections render no tab, while its hand-enumerated sections do.
  • Control: record:details on 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/main 160c6c6eaf)

Ruling

  • Every form surface resolves { group } sections through the one resolver, resolveSectionGroupReferences, which derives from deriveFieldGroupLayout. The fix goes at the shared seam the dialog reaches.
    • ⛔ No re-implementation of the assembly rules.
    • ⛔ No per-page patch.
  • Pins:
    • a tabbed form with a { group } section, which shows that group's tab in the Edit and New dialog;
    • the hand-enumerated sections, as the control.

Related

  • objectui#11541, filed beside this card: record:details edit mode offers no markdown editor. Together the two leave some fields with no editing surface at all.
  • objectui#7051: the original renderer half. Its form-surface claim did not reach this dialog.

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).

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 3, 2026
  2. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01FjqrwXPfSMkSfkKYDSRkN2
    Account: os-zhuang (the seat's linked user as GET /user answers 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 objectui origin/main 6f5719e1c, is a lead for the dev and not an answer. The More actions › Edit / New dialog renders ModalForm directly, from packages/app-shell/src/console/AppContent.tsx and packages/app-shell/src/hooks/useActionModal.tsx. packages/plugin-form/src/ModalForm.tsx takes schema.sections as given and never calls resolveSectionGroupReferences (0 hits in ModalForm.tsx, DrawerForm.tsx, TabbedForm.tsx, WizardForm.tsx, SplitForm.tsx; control: ObjectForm.tsx calls it at withGroups). 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 in sectionGroups.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/objectui printed "no path-derived mandate" for ModalForm.tsx and DrawerForm.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.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    os-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

  4. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR objectui#11551 at head 202a8c0eb (dev report os-dev-report on this card)

    domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-03T13:45Z. Reviewed against GitHub, not the report.

    • Shape: draft, base main. The first line is Fixes #11542 and no other closing keyword appears in the body. Clause-②: no is at line start.
      • 4 files, +366 / −5: ModalForm.tsx, one new pin file, one @object-ui/plugin-form patch changeset and one README paragraph.
      • Inside the claim's surface, plus the README paragraph (docs-driven, accepted).
      • No governed path, no content/docs/releases/.
    • The card's question, answered: a branch before withGroups. AppContent and useActionModal mount ModalForm directly 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: ModalForm resolves once through resolveSectionGroupReferences with ObjectForm's four inputs against the objectSchema it 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.sections reads at the head (:362 the field-group fallback guard, :571 the flat-field effect's early return, :1062 the master-detail hand-off) are section-presence checks or hand-offs to ObjectForm. None draws a section, so none needs the resolved list.
    • 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 resolver ObjectForm uses, 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 no group reaches 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-exports is NOT MEASURED locally (25 unbuilt packages); CI's README Export Check judges it.
    • Out-of-scope: directly mounted DrawerForm does 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 202a8c0eb is green, the seat lands it through the merge queue (pr_ready + automerge_enable).

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed and verified by content: closed completed by PR objectui#11551 · domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-03T14:24Z.

    • The merge: PR objectui#11551 went through the merge queue to main as 584eecae8 at 2026-10-03T14:17Z.

    • Content check on main 584eecae8 against its first parent 9bfd0b36e:

      main parent
      resolveSectionGroupReferences in packages/plugin-form/src/ModalForm.tsx 2 0
      the control export const ModalForm 1 1
      modalFormSectionGroupReference-11542.test.tsx in the tree present 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:dispatched is removed in the same act. domain:ui, area:records, the type and the priority stay.


    Generated by Claude Code

  6. added a commit that references this issue on Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions