Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

console: React warnings in Studio — <div> inside <p> in the package sheet, Select switching uncontrolled→controlled in the create form #11804

Closed

Description

@objectstack-fleet

Filing gate ① — product defect with a named location and a reproduction. reach: Studio package sheet and the Records create form.

Who acts on it: objectui triage → the Studio / app-shell owner. ⛔ Not a claim. Found in a manual browser QA pass of Studio on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.

What happens

  • Package info & settings sheet: "In HTML,
    cannot be a descendant of

    . This will cause a hydration error."

  • Create record form: "Select is changing from uncontrolled to controlled."

Suggested direction (triage to rule)

Replace the <p> wrapper with a <div>; give the Select a defined initial value.

Environment

objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.

Duplicate check

Dedupe words: react warning div descendant of p package sheet · select uncontrolled to controlled

Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    on Oct 7, 2026
  2. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: write metadata — Studio renders valid markup | 缺项 | P3

    Triage: first grade, bug · priority:p3 · domain:ui · area:studio · pm:queue. Direction as the body proposes

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T17:28Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in the Studio package sheet's <p> wrapper and the Records create form's Select ⇒ domain:ui; rationale: a Studio or console surface in objectui. Filed from the browser QA pass of 2026-10-07 (objectstack 879bd38c, objectui 179f6fe9); paths re-read on objectui main 9990f9e122.

    • Why p3: React warnings, no visible fault.
    • Direction:
      • replace the <p> wrapper with a <div>
      • give the Select a defined initial value
    • Clause-②: no. Patch changeset in objectui.
  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 8
    Session: session_01DrKzdPdyLLBW3qpZ4vtk7z
    Account: huangyiirene
    Branch: claude/issue-11804-react-markup-warnings
    Worktree: objectui-issue-11804
    Domain: domain:ui
    Seat: domain:ui#1
    File surface (line numbers on 4e7dd56). Both sites are measured first, and the dev names each file before editing it.

    • The <div> inside <p>: the Package info & settings sheet, which Studio opens from its package menu (engine.studio.pkg.manage, StudioDesignSurface.tsx:1031). It is expected in packages/app-shell/src/views/metadata-admin/PackagesPage.tsx, around its SheetDescription (about :643) or another <p> that wraps a block element. The markup changes only: the <p> becomes a <div>, or the nested block becomes inline.
    • The Select that switches from uncontrolled to controlled: in the Records create form. The dev measures which component renders it (a field widget in packages/fields/src/**, or the form renderer) and gives it a defined initial value. No behaviour change.
    • The tests beside these, and .changeset/11804-*.md.

    ⛔ Not on it:

    • Seat 2's objectui#11792 (claim 6049699621): PackageFormDialog.tsx, PackageIdInput.tsx and CreateItemDialog.tsx.
    • packages/components/src/ui/**, the Shadcn-synced primitives. If the warning comes from a primitive itself, the dev reports instead.
    • objectui#11839's action renderers (area:records, os-support-ai).
    • StudioDesignSurface.tsx, beyond reading where the sheet opens.
    • @object-ui/types, and any package.json.

    Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui over these paths: no path-derived mandate; default tier)
    Clause-②: no
    Responsibility: objectui app-shell and the records create form: Studio's package sheet nests a block element inside <p> ("In HTML, <div> cannot be a descendant of <p>"), and the create form's Select switches from uncontrolled to controlled | the platform path is right: valid markup and a controlled Select from its first render | every user who opens the package sheet or creates a record, measured by the filer in the 2026-10-07 QA pass (React's console warnings)
    Thread-read: 6043210265
    Serial constraints cleared: none blocking.

    Why Clause-②: no: valid markup and a defined initial value. No export, prop, @object-ui/types member, accepted input or packages/i18n key changes.

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
    "issue": 11804,
    "status": "done",
    "branch": "claude/issue-11804-react-markup-warnings",
    "pr": "#11879",
    "session": "session_01DrKzdPdyLLBW3qpZ4vtk7z",
    "premise_still_valid": true,
    "summary": "I reproduced both warnings before editing and fixed each at the component that emits it. H1 was partly wrong: the source is the package sheet's 'Pending changes' header, a p element that holds the draft-count Badge (the Badge primitive renders a div), not SheetDescription. It fires only when the package has pending drafts. The header is now a div with the same classes. H2 was also partly wrong: the source is SelectField's single-value branch (field:select, the type every select gets in the object create form), and it fires on the user's first pick in an unseeded select, not when defaults load. SelectField now gives Radix '' for an undefined value whenever the host passes an onChange, so the Select is controlled from its first render. Saved values are unchanged. A host with no onChange (a bare SDUI node) stays uncontrolled, so its control does not freeze after a pick.",
    "tests": {
    "head": "0fefd45 (every gate, union and ablation below ran on this local HEAD; branch tip on origin = 0fefd45)",
    "merge_commit": "1e4bf56 = merge of origin/main cef0eee (contains 5d69133, checked with merge-base --is-ancestor, exit 0) into the branch, per the PM note; no rebase",
    "files_changed": [
    "packages/app-shell/src/views/metadata-admin/PackagesPage.tsx (header p -> div, same classes)",
    "packages/fields/src/widgets/SelectField.tsx (controlValue: null or (undefined and onChange present) -> '')",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.pendingHeaderMarkup-11804.test.tsx (new pin)",
    "packages/fields/src/widgets/SelectField.controlledFromFirstRender-11804.test.tsx (new pin, 3 hosts)",
    ".changeset/11804-react-markup-warnings.md (patch: @object-ui/app-shell, @object-ui/fields)"
    ],
    "H1": "Measured first: rendered the real PackageDetailSheet in happy-dom and captured console.error. With 1 draft, React logged 'In HTML, %s cannot be a descendant of %s' (div, p) and '%s cannot contain a nested %s' (p, div). The only p holding a div was the 'Pending changes' header p (classes 'flex items-center gap-2 text-xs font-medium uppercase tracking-wide text-muted-foreground') with Badge variant=secondary inside it. With 0 drafts, nothing was logged. SheetDescription holds only the id text. Studio's Package info and settings item opens the same PackageDetailSheet.",
    "H2": "Measured first: ObjectForm in create mode with registerAllFields and an account-shaped schema (industry select with no defaultValue, status select with defaultValue 'prospect'). On mount: no Select warning. After a pick on industry through Radix's hidden native select: console.warn 'Select is changing from uncontrolled to controlled...'. Payload was {status: prospect, name: Acme, industry: finance}. The emitting widget is SelectField (SingleSelectField; trigger testid select-trigger-industry). It passed value undefined to the Radix Select root. Other selects: RecordPickerDialog filter and GridField cell already pass ''. The InlineFieldInput host passes '' and ActionParamDialog passes '?? null'. FieldEditWidget passes the raw value through SelectField, so this fix covers it. The form renderer's BuiltinSelectControl (bare type 'select') logs the same warning on a first pick (measured) and was not changed: see out_of_scope_findings. No shared helper covers both, because toControlValue is also read as 'absent' by the SDUI select renderer's defaultValue and by radio-group.",
    "gates": [
    "pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build (29 projects, covers fields^...) -> exit 0 -> 'STEP build app-shell^... exit=0'; lock VERDICT command-exit 0",
    "pnpm --filter @object-ui/fields type-check -> exit 0 (tsc --noEmit && tsc -p tsconfig.test.json; --listFilesOnly includes the new pin)",
    "pnpm --filter @object-ui/app-shell type-check -> exit 0 (same chain; --listFilesOnly includes the new pin)",
    "pnpm exec vitest run --maxWorkers=2 packages/fields/ + 61 cross-package files (every test naming SelectField, select-trigger- or field:select, plus every PackagesPage test) -> exit 0 -> 'Test Files 302 passed | 1 skipped (303)', 'Tests 4780 passed | 7 skipped (4787)'; lock VERDICT command-exit 0 (held 10m03s, run in the background with a foreground tail --pid wait)",
    "earlier focused run: 7 files (all SelectField* and PackagesPage* tests) -> 'Test Files 7 passed (7)', 'Tests 46 passed (46)'",
    "pnpm check:control-bytes -> exit 0 -> 'check-control-bytes: OK (scanned 7863 tracked text file(s); skipped 85 binary)'",
    "pnpm check:new-line-citations -> exit 0 -> 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'",
    "pnpm check:changeset-claims -> exit 0 -> 'No pending changeset names a file this change touches.'",
    "pnpm check:pending-changeset-literals -> exit 0 -> 'No test source names a pending changeset.'",
    "derived from the diff (new test files, src edits): pnpm check:test-path-roots -> exit 0 OK; pnpm check:unreferenced-sources -> exit 0 'Every shipped source file in every covered package is reachable.'; pnpm check:vi-mock-specifiers -> exit 0 OK",
    "node scripts/check-changeset-presence.mjs -> exit 0 -> '4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'; node scripts/check-changeset-no-major.mjs -> exit 0",
    "eslint --no-inline-config --format json on the 4 touched tsx files -> exit 0: 4 results, 0 errors, 27 warnings (pre-existing no-explicit-any and hook shapes; 6 'as any' in the new test, matching sibling tests). This is a narrowed run: population = the diff's 4 lintable tsx files, count = 4 read from the JSON, and eslint.config.js declares no parserOptions or projectService (no type-aware linting), so this diff cannot change a verdict on an untouched file. Repo-wide pnpm lint is CI's"
    ],
    "ablation": "Run on committed 0fefd45 via objectstack's scripts/ablation-replace.mjs in WRAP mode, with an outer trap that restores from HEAD by absolute path. M1 (header back to p): anchor 1->0, blob 4b0f2c0 -> 7fe6a46; pin result 1 failed / 1 passed; the failure lists React's 'cannot be a descendant of' and 'cannot contain a nested' errors. M2 (delete the undefined branch): anchor 1->0, blob 1d69c56 -> 1010868; 2 failed / 1 passed; both failures show 'Select is changing from uncontrolled to controlled'; host 3 stays green. M3 (unconditional undefined -> '' with no onChange guard): anchor 1->0, blob 1d69c56 -> 08f1112; 1 failed / 2 passed; the no-onChange host stays on the placeholder after the pick. Every direction matched the prediction. Restore: blob after restore == HEAD blob (4b0f2c0 / 1d69c56) and git diff HEAD empty after each leg and at the end. The first M2 attempt was a no-op (its replacement text was a substring of the anchor, so the tool refused and ran nothing) and its reading is void; it was re-run as a --delete leg.",
    "deviations": [
    "Both hypotheses corrected (H1: the Pending changes header, not SheetDescription. H2: fires on the first pick of an unseeded select, not when defaults load). Recorded under H1 and H2.",
    "Per the PM note, merged origin/main (cef0eee, which contains 5d69133) as merge commit 1e4bf56. Then added one test-only commit 0fefd45 that reorders the H1 pin's assertions so a regression shows React's own nesting error first.",
    "Commit trailers use the model-free pair (Claude-Session plus Co-authored-by: Claude), not the harness's model-named trailer, per os-dev and AGENTS.md. The PR body ends with the os-dev session-URL footer rather than the harness's footer.",
    "The first M2 ablation leg was a refused no-op; it was re-run as a delete leg (see ablation).",
    "BuiltinSelectControl has the same warning and was not fixed. Fixing it would add @object-ui/components to the verification surface (fails bounded-fix condition 4). It is noted in the PR's Acceptance notes.",
    "Open-PR overlap read: 9 open objectui PRs (11870 11869 11868 11867 11856 11845 11844 11600 11069); none touches SelectField.tsx, PackagesPage.tsx or form.tsx. Positive control: 23 tsx paths in the same file listing."
    ]
    },
    "mcp_calls": "0 (no MCP GitHub tool used, read or write)",
    "api_writes": "2: (1) pr_create through the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls (draft forced), created objectui#11879; read-back 8242 bytes sent = 8242 stored, identical. (2) This os-dev-report comment through post-stamped: POST /repos//issues/11804/comments. Also git push to one branch (empty-branch probe plus two pushes; not REST). Zero label or assignee writes. Reads were single REST GETs (card, thread, open PRs and their files, the PR read-back).",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier:承接者:无 · noted in the PR's Acceptance notes, not filed. Same family as this card: the form renderer's built-in select branch (BuiltinSelectControl, packages/components/src/renderers/form/form.tsx) passes toControlValue(value), which is undefined for an unseeded field, so a first pick on a bare type 'select' form field logs 'Select is changing from uncontrolled to controlled'. Measured in happy-dom through the real form renderer. The fix would be the same shape (?? '' at that call site, not in the shared toControlValue). No public door or real producer was measured (the object create form never reaches it), so it lacks reach: for filing. Dedupe words: built-in select uncontrolled to controlled form renderer · BuiltinSelectControl toControlValue undefined · bare select form field warning"
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — PR objectui#11879 (head 0fefd45)

    domain:ui seat 1 · session_01DrKzdPdyLLBW3qpZ4vtk7z · reviewed against the PR's file list and diff, git merge-tree, its check runs and the dev's report 6051728326, read 2026-10-08T03:45Z.

    • Shape: draft → main. The first line is Fixes #11804, and Clause-②: no starts a later line.
    • Scope: 5 files, +319/−9, inside claim 6051109461's surface. Both sites were measured first, and the files were named before editing.
      • PackagesPage.tsx (+10/−4): the package sheet's Pending changes header <p> becomes a <div> with the same classes.
      • packages/fields/src/widgets/SelectField.tsx (+30/−5): the control value becomes '' for undefined when the host passes onChange.
      • Two pins, and one changeset (@object-ui/app-shell and @object-ui/fields patch).
      • packages/components/src/ui/** is untouched.
    • Both hypotheses corrected by measurement, accepted:
      • H1. The emitter is the Pending changes header <p> that holds the draft-count Badge (which renders a <div>), not SheetDescription. It fires only when the package has pending drafts. Studio's Package info & settings opens the same sheet.
      • H2. The emitter is SelectField's single-value branch (field:select, which every select in the object create form gets). It fires on the first pick of an unseeded select, not when defaults load.
      • A host that passes no onChange (a bare SDUI node) stays uncontrolled, so its control does not freeze after a pick. That is pinned (ablation M3).
    • Clause-② re-read: no export, prop or type changes. SelectField's props are unchanged; only the value it hands Radix differs, so display and saved values are unchanged. no holds.
    • Tests:
      • Local union on 0fefd45 (with main cef0eee merged in): 302 files and 4780 tests green across packages/fields and every test that names SelectField, select-trigger- or field:select, plus PackagesPage. Both type-checks and the derived check:* set are green.

      • Ablation, three legs, each in the predicted direction:

        • M1, the header back to <p>: React's nesting errors return.
        • M2, the undefined branch removed: "Select is changing from uncontrolled to controlled" returns.
        • M3, the onChange guard dropped: the bare host freezes on its placeholder.

        Each restore was proven by blob hash.

    • Overlap: an in-memory git merge-tree is clean against main and against objectui#11868, fix(app-shell): the form designer's drag live region names labels and places, not ids (objectui#11802) #11869 and fix(app-shell,console): zh names a Studio pillar by its tab label; settings label probes stop logging missing-translation warnings (objectui#11801) #11870.
    • CI at 0fefd45: converging, none red at this read. The PR is queued when every check completes.
    • Out-of-scope, noted, not filed: the form renderer's BuiltinSelectControl (bare type: 'select', packages/components/src/renderers/form/form.tsx) logs the same warning on a first pick. It was measured in happy-dom, but no public door was measured (the object create form never reaches it). It is in the PR's Acceptance notes.
    • PR assignee: set by this seat to huangyiirene.

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11879 → main 3035948

    domain:ui seat 1 · session_01DrKzdPdyLLBW3qpZ4vtk7z · verified 2026-10-08T04:23Z.

    • Merged through the merge queue at 2026-10-08T04:23:06Z, after it was queued at 2026-10-08T04:06:43Z.
      • CI on head 0fefd45 before queueing: 40 of 43 check runs passed, and the 3 skipped are the expected ones.
      • check-governed-merges.mjs: not governed, +319/−9.
    • Content check: 3035948 is one squash commit on parent 99c481d. It changes 5 files, +319/−9, and all 5 are blob-identical to the reviewed head 0fefd45. The whole diff's patch-id matches (be8c9592…).
    • Card: closed completed by the PR's Fixes. pm:dispatched was removed in the same pass and read back.
    • On record:
      • Both emitters were measured before the fix. One is the package sheet's Pending changes header <p> holding a Badge. The other is SelectField's first pick on an unseeded select.
      • The form renderer's BuiltinSelectControl has the same warning shape, with no measured public door. It is noted in PR objectui#11879's Acceptance notes and not filed.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions