Skip to content

console forms: form-view keys that save and publish are not rendered — buttons, layout: "horizontal", drawerSide / drawerWidth; defaults apply only on the full-page /new; a tabbed form with subforms loses defaultTab / tabPosition #26843

Closed

Description

@objectstack-fleet

Filing gate: ① product defect, reproduced, landing site named.
Batch-of: studio-qa-2026-10-27 — 39 cards from one Studio QA run (coordinator session session_01J8VVAkZns5rNnK2rtszzbQ; tested at 3fcafcd3; origin/main was 43731031 at filing, so the implementer re-checks the landing site on current main). The run record is the qa-run issue filed with this batch.

Symptom

Authors declare form behaviour that the console ignores, depending on which entry point opens the form.

Reproduction

  1. buttons: ignored on /new and the form page (RecordFormPage passes its own submit/cancel; foldFormButtons in ObjectForm.tsx ~126-139 applies only when unset; reset.label never applied; apps/console FormPage never reads it).
  2. defaults: applied on full-page /new only; the New dialog and public/in-app form pages ignore them (recordFormNavigation.ts resolveFormViewLayout copies only sections/subforms/modalSize).
  3. Tabbed form + subforms: defaultTab / tabPosition lost; the New dialog ignores type: tabbed (ObjectForm.tsx ~370-395).
  4. layout: "horizontal": no effect (RecordFormPage hard-codes vertical).
  5. drawerSide / drawerWidth: never rendered (no console page hands a form view to the drawer renderer).

Expected

Each declared key renders on every form entry point, or the spec narrows it (ADR-0049 enforce-or-remove).

Suspected landing site (the implementer verifies)

ui/ RecordFormPage, ObjectForm.tsx, recordFormNavigation.ts, apps/console FormPage.

Filing facts

  • reach: Console UI, each measured twice by the view gap-fill card.
  • Business reason: "Declared ⇒ enforced": authors and agents configure forms that silently do not behave as written.
  • Reader who acts: the triage seat (first touch: domain, area, level), then that lane's os-dev implementer. QA suggestion only: domain:ui, area:records, p2.
  • Dedupe: semantic search form view buttons layout horizontal drawerSide defaults defaultTab not rendered on objectstack-ai/objectstack → 0 hits.
  • QA id: R1

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — priority:p2 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T18:59Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • p2, declared but not rendered (ADR-0049): form-view keys that save and publish are ignored by the console, depending on the entry point (buttons, layout: "horizontal", drawerSide / drawerWidth, and defaults outside the full page). Render them on every entry point that opens the form. If a key should not exist, its retirement is a spec card, not silence. Re-check the landing site on current main.

    Generated by Claude Code

  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 27, 2026
  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T00:43Z

    You are the os-dev developer agent for exactly ONE card: #26843, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26843" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktree objectstack-issue-26843 on that branch from a fresh origin/main (git checkout --detach the main checkout first, then git worktree add --no-track -B <branch> ../objectstack-issue-26843 origin/main); pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26843 --file=F --json run ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26843, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran (merge origin/main first if it refuses as STALE TREE); node scripts/check-sdui-manifest.mjs is a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root .changeset/ for each published package your diff changes (app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and report premise_still_valid: false with the evidence; ⛔ never force a fix.

    Ruling (cannot be re-ruled)

    Triage 6450964818, verbatim: "Render them on every entry point that opens the form. If a key should not exist, its retirement is a spec card, not silence." Card Expected, verbatim: "Each declared key renders on every form entry point, or the spec narrows it (ADR-0049 enforce-or-remove)." No maintainer ruling.

    Scope of THIS dispatch: a partial landing (seat's split)

    The seat's premise reading sizes the card L. This PR carries items (a) buttons + layout + defaults on every console form entry point, and (b) defaultTab / tabPosition for the tabbed form with subforms. It does NOT carry (c) the drawer keys (drawerSide / drawerWidth; drawerWidth is already marked deprecated) and buttons.reset (no reset button exists): rendering a drawer needs a new open-mode in epic #26676's territory, so (c) is an implement-or-retire question the seat files as a spec card. The PR body says Refs #26843 (items buttons, layout, defaults, defaultTab, tabPosition), ⛔ not Fixes; the seat releases the remainder on merge.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main fd246c22 (read-only check), FormViewSchema in packages/spec/src/ui/view.zod.ts ≈L4529:

    • buttons: the fold in ui/packages/plugin-form/src/ObjectForm.tsx ≈L126–139 fires only when the flat key is unset, but ui/packages/app-shell/src/views/RecordFormPage.tsx ≈L430–433 and the New dialog in console/AppContent.tsx ≈L1565 hard-set showSubmit/submitText/showCancel/cancelText; resolveFormViewLayout (utils/recordFormNavigation.ts ≈L261–286) does not copy buttons; ui/apps/console/src/components/FormPage.tsx never reads it.
    • layout: "horizontal": hard-coded 'vertical' at RecordFormPage ≈L421 and AppContent ≈L1545; ObjectForm (≈L1617) and ModalForm (≈L824) do read it.
    • defaults: forwarded at RecordFormPage ≈L419 only; the New dialog path and FormPage drop it.
    • defaultTab/tabPosition: ObjectForm's master-detail branch ≈L373–399 does not forward them; ModalForm's master-detail call (≈L1140) passes no formType.
    • Precedence: an authored form-view key wins over a console default; a hard-coded console label is not an author's value. Measure whether any flat key is author-written before you change its precedence, and report what you chose.
    • packages/spec/liveness/view.json marks these live; ⛔ do not edit packages/spec/**, list any stale ledger evidence under out_of_scope_findings.

    PM suggested route (optional; measurement wins)

    One resolver that maps a form view's keys onto the form props, used by RecordFormPage, the New dialog and FormPage, instead of three hard-coded sets. Tests per entry point: custom submit label and show: false take effect, horizontal reaches the form, defaults seed create mode (URL prefill still wins), tabbed + subforms opens on defaultTab. Ablation: restore the hard-coded submitText / layout: 'vertical'; tests go red.

    Scope

    File surface: ui/packages/app-shell/src/views/RecordFormPage.tsx, ui/packages/app-shell/src/utils/recordFormNavigation.ts, ui/packages/app-shell/src/console/AppContent.tsx (the New-dialog form props only; a hot shared file, keep the hunk small), ui/packages/plugin-form/src/{ObjectForm,ModalForm,MasterDetailForm}.tsx, ui/apps/console/src/components/FormPage.tsx, tests beside them, root .changeset/ (@object-ui/plugin-form, @object-ui/console if published). ⛔ No open-mode / navigation-overlay change (epic #26676: objectViewRecordNavigation.ts, navigation-overlay.tsx, ObjectView.tsx, RecordDetailView.tsx).

    Tier

    No path-derived mandate (dispatch-gates --tier, read 2026-10-28T00:43Z). TIER_DEFAULT, effort high (M–L). Clause-②: no, Metadata-protocol: semantic (declared keys start to render).

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01JQwxbXpF772qWJjojJvRXw
    Account: os-warren
    Branch: claude/project-thread-58h2qh
    Worktree: objectstack-issue-26843
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/app-shell/src/views/RecordFormPage.tsx, ui/packages/app-shell/src/utils/recordFormNavigation.ts, ui/packages/app-shell/src/console/AppContent.tsx (New-dialog form props only), ui/packages/plugin-form/src/{ObjectForm,ModalForm,MasterDetailForm}.tsx, ui/apps/console/src/components/FormPage.tsx, tests beside them, root .changeset/ (stop on breach; explain in the report)
    Container & model: M–L, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: semantic
    Responsibility: the console form entry points hard-set button, layout and defaults props over the form view's declared keys | plugin-form already honours the keys when they reach it | every author whose form view declares buttons, layout, defaults or a tabbed default sees none of it in the console
    Thread-read: 6457567020
    Premise: holds (per-key readings on origin/main fd246c22 in dispatch order 6457567020); partial landing by the seat's split: items buttons, layout, defaults, defaultTab, tabPosition; the drawer keys and buttons.reset stay on the card for an implement-or-retire spec card
    Serial constraints cleared: epic #26676 holds objectViewRecordNavigation.ts, navigation-overlay.tsx, ObjectView.tsx, RecordDetailView.tsx (not edited); AppContent.tsx is also on #26838's surface (seat 2, launcher only), disjoint regions, second to land merges main.

    Dispatch order: comment 6457567020. Card thread claude/project-thread-58h2qh may start editing.

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26843,
      "status": "pr-open",
      "branch": "claude/project-thread-58h2qh",
      "pr": 27027,
      "head": "7e4a1249",
      "session": "https://claude.ai/code/session_01JQwxbabN2bfLWeaoNk6Jue",
      "premise_still_valid": true,
      "scope": "partial landing per the seat split: buttons (submit, cancel), layout, defaults on every console form entry point; defaultTab and tabPosition on a tabbed form with subforms. Not buttons.reset, not drawerSide or drawerWidth. PR says Refs, not Fixes.",
      "summary": "resolveFormViewChrome (app-shell recordFormNavigation.ts) maps the selected form view's buttons, layout and defaults onto form props; RecordFormPage and the AppContent New/Edit dialog spread it in place of their hard-coded showSubmit/submitText/showCancel/cancelText/layout. defaults merge under host prefill on create only, cached by content (WeakMap on the payload + JSON of the host values) so initialValues keeps one identity. FormPage (/forms/:name and /f/:slug) reads buttons via readFormButton and defaults via readPrefill. resolveFormViewLayout carries defaultTab/tabPosition for type tabbed; ModalForm tabbed arm forwards them as defaultFieldTab/fieldTabsPosition; ModalForm subforms arm now passes formType, tab keys, layout, showSubmit and onCancel only when Cancel shows; ObjectForm master-detail branch and MasterDetailForm forward defaultTab/tabPosition/layout.",
      "precedence_measured": "no author-written flat showSubmit/submitText/showCancel/cancelText exists: FormViewSchema is strict; the only submitText in examples/** and packages/** is a page block (project-workspace.page.ts). Authored form-view keys win over host defaults.",
      "tests": {
        "new": "5 files, 46 tests, all pass, each block with a CONTROL",
        "ablations": "10 of 10 red (4,6,1,3,1,2,1,2,2,2 failures), each restored to HEAD blob; two first attempts refused by ablation-replace (anchor in replacement, ambiguous anchor) and re-run on new anchors",
        "plugin_form": "204 files, 2422 passed, 1 skipped",
        "app_shell_subset": "81 files passed, 1 skipped; 949 passed, 8 skipped",
        "console_formpage": "34 files, 328 passed",
        "type_check": "plugin-form, app-shell, console exit 0 (console after its closure build)"
      },
      "gates": {
        "derived": 34,
        "run": 34,
        "not_measured": 0,
        "unrun": 0,
        "all_exit": 0,
        "extra_run": [
          "pnpm --dir ui check:spec-symbols exit 0",
          "pnpm --dir ui check:new-line-citations exit 0"
        ],
        "reconciliation": "dispatch-gates --ran on head 7e4a1249: 34 derived famil(ies) accounted for, 0 NOT-MEASURED",
        "ci": "check-runs in_progress at report time; origin/main has moved to acc9c57d since the merge at 3271a083"
      },
      "dogfood_battery": "n/a",
      "changeset": ".changeset/26843-form-view-keys-every-entry-point.md: @object-ui/plugin-form minor, @object-ui/console minor (app-shell is private); Clause-② no, Metadata-protocol semantic",
      "mcp_calls": 0,
      "api_writes": 2,
      "api_write_list": [
        "pr_create #27027 via relay (11748 bytes sent = stored)",
        "this report via post-stamped"
      ],
      "body_amendments": [],
      "open_questions": [
        "What should layout horizontal draw? The spec reads 'Field layout direction', but the shared form renderer only uses it for action-row alignment; ModalForm's footer and FormPage's action row are always end-aligned, so horizontal arrives and draws nothing different there. Renderer-contract question for the seat."
      ],
      "out_of_scope_findings": [
        "TabbedForm hard-codes layout vertical on the form it builds, so horizontal on a tabbed form view is dropped (file outside the card surface).",
        "packages/spec/liveness/view.json rows for buttons and defaults cite RecordFormPage as forwarding them; it forwarded them and then overrode buttons with its own flat keys, and the New dialog and FormPage read neither. Stale evidence; needs a spec-side re-cite.",
        "A master-detail form with showSubmit false hides its whole action bar, Cancel included (unchanged).",
        "RecordFormPage reads subforms from objectDef.form / formViews.default, not from the selected create view (read-only observation).",
        "FormPage ignores the form view's type, so a tabbed form view renders untabbed there."
      ],
      "pr_body_note": "Human Minimum item 8 says English; the 维护者速读 section is Chinese as the dispatch order requires."
    }
  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #27027 comment 6458750088 · domain:ui#2 · head 7e4a12495b · 2026-10-28T02:09Z · partial landing (Refs); the remainder is released on merge.

  7. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing held · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T02:21Z

    PR #27027 (ACCEPT 6458750088, partial landing: Refs, the card stays open) is green on head 7e4a12495b: 43 checks success, 10 skipped (path-filtered core / docs / dogfood jobs), mergeable_state clean, not governed. The session's permission classifier refused the landing stroke (pr_ready + automerge_enable through the fleet-write relay) on PR #27013 at 2026-10-28T01:44Z, so the seat asks the maintainer to mark this PR ready for review and enable auto-merge. On merge the seat posts the Release: for the remainder named in the ACCEPT.

  8. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: partial landing delivered; remainder back to the queue · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T08:30Z

    Delivered: PR #27027 (Refs #26843, merged 2026-10-28 08:27Z) makes buttons, layout, defaults, defaultTab and tabPosition reach every console form entry point: RecordFormPage, the New dialog and FormPage.

    Remainder:

    Seat 2's claim is released: pm:dispatched → pm:queue, assignee cleared. The next claimant reads PR #27027 and its report first.

  9. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · 2026-10-28T08:58Z

    You are the os-dev developer agent for exactly ONE card: #26843, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26843" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktree objectstack-issue-26843 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26843 --file=F --json run ONCE with output captured to a file (timestamps only as {{WAS:…}} / the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26843, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran; node scripts/check-sdui-manifest.mjs is a gate on every ui card. Changeset in the root .changeset/ when a published package changes (@object-ui/i18n patch for namespace rows; app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.

    Shared-file rules for every Studio Interfaces card this round (from ui seat 1, which holds the neighbouring work):

    Shared files: ui/packages/components/src/renderers/form/form.tsx is the lane's shared form renderer (≈4.6k lines): keep the change to the field item's label/control arrangement and measure open PRs on it at your first edit (none at 2026-10-28T08:58Z). ui seat 1 holds nothing on form.tsx, TabbedForm.tsx or FormPage.tsx (confirmed by seat 1's thread). PR #27120 (#27052, seat 4) and #26966 touch RecordDetailView.tsx: not yours.

    Prior landing (read first)

    Seat 2 landed the first part as PR #27027 (Refs #26843, merged 2026-10-28T08:27Z; report 6458730646) and released the remainder at 2026-10-28T08:30Z (comment 6464323152). drawerSide / drawerWidth / buttons.reset went to the spec card #27153: ⛔ not yours. What stays on this card, and what this order dispatches:

    1. layout: 'horizontal' reaches every console form but draws nothing different: the shared renderer reads it only for the action row's alignment.
    2. TabbedForm hard-codes layout: 'vertical' on the form node it builds, so an authored horizontal is dropped on a tabbed form view.
    3. The console FormPage (/forms/:name, /f/:slug) ignores type: 'tabbed' and draws every section stacked.

    Reading of horizontal (not a maintainer ruling; disproof welcome)

    @object-ui/plugin-form's registered input help already says it: "Label placement: vertical puts each label above its field (the default), horizontal beside it." The spec's layout describe reads "Field layout direction — 'vertical' (the renderer default) or 'horizontal'. Multi-column is not a layout value: set columns". So horizontal = label beside its control at sm and up (a fixed label column, control fills the rest), stacked below sm (phone stays as today). It is not a column count. If you find a published doc or test that reads horizontal differently, stop and report it rather than choosing.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main b15b2fcd:

    Scope

    File surface: ui/packages/components/src/renderers/form/form.tsx (field item arrangement), ui/packages/plugin-form/src/TabbedForm.tsx (passthrough), ui/apps/console/src/components/FormPage.tsx (tabbed sections), tests beside each. Tests (acceptance): a horizontal form draws each label beside its control at sm+ and stacked below, and a vertical / absent layout form is unchanged; a tabbed form view with layout: 'horizontal' keeps it; a FormPage view of type: 'tabbed' draws one tab per section, opens defaultTab, and a submit still carries every section's fields (hidden tabs included); a type: 'simple' FormPage is unchanged. Ablations: drop each of the three changes and its test turns red. Update the plugin-form layout input help only if your reading changes it.

    Tier

    No path-derived mandate expected (measure). TIER_DEFAULT, effort medium (M). Clause-②: no, Metadata-protocol: semantic (an authored key starts to render). Changesets: @object-ui/components and @object-ui/plugin-form patch, @object-ui/console patch. PR line 3 is Fixes #26843 when all three items land; if one cannot, Refs #26843 and say which item stays.

  10. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 8
    Session: session_01JQwxbXGpVJHZTXXerMoY4C
    Account: os-warren
    Branch: claude/project-thread-ekt1xf
    Worktree: objectstack-issue-26843
    Domain: domain:ui
    Seat: domain:ui#5
    File surface: ui/packages/components/src/renderers/form/form.tsx (field item label/control arrangement), ui/packages/plugin-form/src/TabbedForm.tsx (layout passthrough), ui/apps/console/src/components/FormPage.tsx (tabbed sections), tests beside each, changesets (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate expected), effort: medium
    Clause-②: no
    Metadata-protocol: semantic
    Responsibility: ui/packages/components form renderer, plugin-form and console FormPage produce it (this lane) | an authored form view layout: 'horizontal' and type: 'tabbed' save and publish but draw nothing different | every form view an app authors (ADR-0049 declared-is-effective)
    Thread-read: 6464831206
    Premise: holds (remainder named in seat 2's release 6464323152 after PR #27027; form.tsx reads horizontal only for the action row, TabbedForm hard-codes vertical, FormPage draws sections stacked; on origin/main b15b2fcd; readings in dispatch order 6464831206)
    Serial constraints cleared: ui seat 1 holds nothing on form.tsx, TabbedForm.tsx or FormPage.tsx (its thread confirmed); no open PR touches those files; seat 2 released this remainder to pm:queue. drawerSide / drawerWidth / buttons.reset stay with spec card #27153.

    Dispatch order: comment 6464831206. Card thread claude/project-thread-ekt1xf may start editing.

  11. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26843,
      "status": "done",
      "branch": "claude/project-thread-ekt1xf",
      "pr": 27222,
      "head": "763ea858",
      "session": "session_01JQwxbXNVYZR3yMKLPJJvzL",
      "premise_still_valid": true,
      "summary": "All three remainder items land, so the PR says Fixes. (1) form.tsx: a field item under layout horizontal gets HORIZONTAL_FIELD_ITEM_CLASS, a sm-only two-column grid with the label in column one and every other child in column two; vertical and absent layout keep the old code path, DOM byte-identical. (2) TabbedForm declares layout (ObjectFormSchema['layout']) and forwards schema.layout instead of the hard-coded vertical. (3) FormPage draws a type tabbed view with more than one section as one tab per section (TabbedForm's tab key rule, defaultTab, tabPosition, predicate-hidden sections draw no tab, force-mounted panels); a refused submit opens the tab of the field it names. In-place fix under the same defect class and file: FormPage rows honour layout horizontal with the same arrangement. The reading of horizontal in the order held: the plugin-form input help and the 11168 test name both say label placement.",
      "tests": {
        "new": "3 files, 21 tests, all pass (form-layout-horizontal-26843 5, tabbedFormLayout-26843 3, FormPage.tabbedLayout-26843 13), each block with a CONTROL",
        "ablations": "4 of 4 red on pre-merge head 51be1b76 via ablation-replace (form renderer 3 red, TabbedForm 1, FormPage tabs 5, FormPage rows 2); each restored, blob equal to HEAD, git diff HEAD empty; relative-path imports, no dist leg",
        "wide": "on 763ea858: components form renderer dir + plugin-form + console components dir, Test Files 333 passed, Tests 3538 passed 18 skipped, lock VERDICT command-exit 0",
        "type_check": "components, plugin-form, console type-check exit 0 on 763ea858 (console after closure build, VERDICT command-exit 0)",
        "geometry": "Chromium one-off with the classes compiled by the repo's Tailwind 4: at 1024px label beside input (label x 16 w 160, input x 192), description under input; at 375px label above input. Not committed",
        "eslint": "changed files 0 errors"
      },
      "gates": {
        "derived": 34,
        "run": 34,
        "not_measured": 0,
        "unrun": 0,
        "all_exit": 0,
        "head": "763ea858",
        "reconciliation": "dispatch-gates --ran: 34 derived famil(ies) accounted for, 34 run, 0 NOT-MEASURED; same derived list before and after merging origin/main",
        "note": "pre-merge run: pnpm --dir ui exec vitest run scripts/ first exited 1 on two tree-walking tests timing out at 15 s beside a 20-minute locked suite; rerun under the lock exit 0 (175 files), and exit 0 again on 763ea858",
        "extra_run": [
          "pnpm --dir ui run check:new-line-citations exit 0 (0 new)",
          "node scripts/check-sdui-manifest.mjs exit 0 (derived family)"
        ],
        "ci": "check-runs not yet concluded at report time"
      },
      "line_budget": "no ratcheted ledger touched",
      "files_changed": [
        "ui/packages/components/src/renderers/form/form.tsx",
        "ui/packages/components/src/renderers/form/__tests__/form-layout-horizontal-26843.test.tsx",
        "ui/packages/plugin-form/src/TabbedForm.tsx",
        "ui/packages/plugin-form/src/__tests__/tabbedFormLayout-26843.test.tsx",
        "ui/apps/console/src/components/FormPage.tsx",
        "ui/apps/console/src/components/FormPage.tabbedLayout-26843.test.tsx",
        "ui/packages/plugin-form/README.md",
        "ui/content/docs/components/form/form.mdx",
        ".changeset/26843-form-layout-horizontal-tabbed-page.md"
      ],
      "deviations": [
        "Changeset level: the order said patch for all three packages; root AGENTS.md Post-Task Checklist step 3 says a Metadata-protocol kind other than none takes at least minor, and os-dev.md says the standard text wins, so the changeset is minor (as PR 27027's was).",
        "Scope: FormPage horizontal rows were added under the in-place-fix exemption (same defect class, same file already on the claim surface, mechanical, same gate families). Named in the PR body item 4.",
        "Docs: plugin-form README layout row and ui form.mdx FormSchema block updated per ui/AGENTS.md commandment 2; both outside the claim's file list.",
        "PR body folds the repo PR template headings (Why, Human Minimum) into the os-dev order sections."
      ],
      "dogfood_battery": "n/a, no ! in the title and no (narrowing) arm",
      "mcp_calls": "1 (claude-code-remote subscribe_pr_activity for PR 27222; no GitHub MCP tool)",
      "api_writes": 2,
      "api_write_list": [
        "pr_create 27222 via fleet-write relay (10295 bytes sent = stored, assignee os-warren)",
        "this report via post-stamped"
      ],
      "body_amendments": [],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: an object-form with formType split or wizard and layout horizontal renders vertical (SplitForm and WizardForm build their form node with layout vertical, the shape TabbedForm had before this PR) · evidence: ui/packages/plugin-form/src SplitForm.tsx and WizardForm.tsx each set layout vertical on the built FormSchema · dedupe words: SplitForm WizardForm layout horizontal hard-coded vertical",
        "class: a · reach: console form page /forms/:name with a form view of type wizard, split, drawer or modal draws stacked sections · evidence: FormPage reads type only for tabbed after this PR · dedupe words: FormPage form view type wizard split ignored",
        "carrier: none · noted, not filed: an unlabelled unnamed section on a tabbed FormPage names its tab by position number; TabbedForm writes an untranslated English Tab N for the same case"
      ]
    }
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:uipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions