Repository navigation
plugin-form: the record:line_items registration requires childObject, so the page compile refuses a dataSource-bound node that the spec row accepts (missing-required-prop at the save gate) #11569
Description
Filing gate: class (b): a registration's requiredness contradicts the spec row it publishes. reach: public door, measured: the JSX page compile, whose ok is the save gate. Reader: triage grades and routes it.
Filed by domain:ui seat 1 (session_01FjqrwXPfSMkSfkKYDSRkN2, seat post objectui#5560). It comes from the out-of-scope finding in the objectui#10872 dev report (5972001469), and is the reading this seat carried as 5970613848 on objectui#11536. Re-read by this seat at objectui origin/main ab18797. ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.
What happens
@objectstack/spec17.6.0'sComponentPropsMap['record:line_items']makeschildObjectoptional, "because the component-level dataSource binding can supply it instead". objectuimainresolves 17.6.0.- The runtime agrees with the row. In
packages/plugin-form/src/index.tsx,RECORD_LINE_ITEMS_DATA_SOURCEmaps the binding's object tochildObject(object: 'childObject', about:563–:568atab18797). The renderer is wrapped inelementDataSourceBlock. - The registration's
inputsdeclare{ name: 'childObject', type: 'string', required: true }(about:604). - So the page compile and
validateTree, which read the registration manifest, refuse a node that the spec row, the zod faces and the runtime all accept.
Measured (the objectui#10872 dev, a one-off console probe, deleted before commit)
- Subject:
sdui-parsercompile()over the real registry manifest (manifestFromConfigs(ComponentRegistry.getAllConfigs())), with arecord:line_itemsnode that hasdataSource.objectand nochildObject. - Result:
missing-required-propforchildObject, at error severity, andok = false.validateTreeanswers the same. - The other faces: for the same node,
objectui validate's command function (the zod faces, run from source against the built@object-ui/types) answers "Schema is valid" and exits 0. - Control: the same node with
childObjectcompilesok = true, with 0 diagnostics. - Side reading, not this card: a node with neither
childObjectnor a binding passes the zod faces and the spec row, and the runtime shows a visible config hint (pinned byLineItemsPanel.childObjectDecline).
Seam
spec:ComponentPropsMap['record:line_items'].childObject (optional) → plugin-form registration inputs (required: true) → sdui-parser validateTree missing-required-prop.
Likely landing (a lead, not a ruling)
The spec row decides: spec declaration > implementation. The registration's childObject loses required: true, so the page compile accepts a bound node, matching the row and the runtime. Two consequences to check:
- whether the manifest can state the either-or (a
childObjector a binding) rather than dropping requiredness outright; - whether
apps/console/src/__tests__/registry-inputs-spec-parity.test.tsbooks this difference. PR objectui#11557 set its caps today.
Dedupe
- REST: the 300 most recently updated objectui issues and PRs (since 2026-09-20), grepped for
childObject|line_items|line-items|missing-required-prop. Hits: objectui#11536 and PR objectui#11557, neither about requiredness. - MCP semantic search, repo-scoped: "line items childObject required" returned objectui#6188 and
record:line_itemsalso issuesfind(undefined, …)for a panel whosechildObjectis unset — the sibling of #6188 in the same component #6194, both closed and both about fetches with an unsetchildObject, not this. A second query, "record:line_items childObject required registration refuses dataSource bound node missing-required-prop page compile", returned 0 hits. - Dedupe words:
record:line_items childObject required inputs·missing-required-prop childObject dataSource binding·line_items registration required vs spec row optional.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 3, 2026
Triage: first grade —
bug·priority:p3·domain:ui·area:records·pm:queue. The spec row decides: the registration stops requiringchildObjectwhen a binding can supply itTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-03T18:54Z. ⛔ Not a claim, ⛔ not a dispatch.Measured now:
packages/plugin-form/src/index.tsxon objectuiorigin/mainab18797215(about:604) declares{ name: 'childObject', type: 'string', required: true }.ComponentPropsMap['record:line_items']makeschildObjectoptional "because the component-level dataSource binding can supply it" (packages/spec/src/ui/component.zod.ts, about:2177).childObject.Why p3. The refusal is loud, at the save gate, and one key works around it. Nothing is lost silently. It is still a second authority that contradicts the row it publishes.
Routing: the
plugin-formregistration, sodomain:ui.Direction: spec declaration over implementation.
childObjector a binding), the registration states it.childObjectlosesrequired: true. The runtime's visible config hint for a node with neither (pinned byLineItemsPanel.childObjectDecline) stays the answer there.registry-inputs-spec-parity.test.ts: if it books this difference, the booking goes with the fix.dataSource-bound node with nochildObjectcompilesok;childObjectcontrol still compiles;Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Claim: PM loop round 8
Session:
session_01FjqrwXPfSMkSfkKYDSRkN2Account:
os-zhuang(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11569-line-items-childobjectWorktree:
objectui-issue-11569Domain:
domain:uiSeat:
domain:ui#1File surface: triage
5972410418(spec declaration over implementation), read at objectuiorigin/main2e818d0as leads:packages/plugin-form/src/index.tsx(therecord:line_itemsregistration, about:604):childObjectstops beingrequired: true, or states an EXISTING "one of these is required" vocabulary if the manifest has one; ⛔ no new vocabulary;apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, only if it books this difference;ok, thechildObjectcontrol, the neither-node's runtime hint); one@object-ui/plugin-formpatchchangeset.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" for these paths)Clause-②: yes
Why: the registration's
inputsare what the page compile (the save gate) enforces, so droppingrequired: truewidens that gate's accept set for adataSource-bound node, which the spec row already accepts. An at-tier contract review follows the dev's report.Thread-read: 5972410418
Serial constraints cleared: read 2026-10-04T07:56Z.
packages/plugin-form/**orregistry-inputs-spec-parity.test.ts. objectui#8347 (domain:spec, in flight) holdspackages/types/src/**; this card does not editpackages/types.packages/plugin-detail) and objectui#11546 (metadata-admin/previews/FlowCanvas.tsx) are claimed in this act, with disjoint files.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{
"issue": 11569,
"status": "done",
"branch": "claude/issue-11569-line-items-childobject",
"pr": "#11604",
"session": "session_01FjqrwXPfSMkSfkKYDSRkN2 (mode:subagent; the parent PM session id, as the claim names it)",
"premise_still_valid": true,
"summary": "The
record:line_itemsregistration (packages/plugin-form/src/index.tsx) no longer declareschildObjectrequired. It now publishes a description: the node'sdataSourcebinding can name the object (dataSource.objectlands on the key and outranks an authored value), and with neither the panel shows its config hint. The vocabulary question was measured. ComponentInput and ManifestInput carry only a booleanrequired, andbinding: 'object'marks an object-naming input, not requiredness. So no either-or form exists, and per the rulingrequiredis dropped with no new vocabulary and no packages/types edit. Red was reproduced first at the shipped sdui.manifest.json: a bound node failed with missing-required-prop at error, ok false. Pinned green, ablated red, restored by blob hash. registry-inputs-spec-parity books no requiredness (hypothesis 4 falsified), so it is unchanged. Draft PR #11604 is open, with assignee os-zhuang and labeler labels only.","tests": "All at head 448bac5. (1) REPRODUCE: the new pin apps/console/src/tests/line-items-bound-child-object-11569.test.ts ran on unfixed source: 4 failed / 1 passed. Row 2 received [error, missing-required-prop, 'record:line_items is missing required prop childObject']. Row 4 was then re-cut into a true before/after control. (2) GREEN: the pin plus LineItemsPanel.childObjectDecline.test.tsx: 'Test Files 2 passed (2) / Tests 10 passed (10)'. (3)
pnpm --filter '@object-ui/plugin-form^...' build: VERDICT command-exit 0 (Scope: 12 of 47).pnpm --filter @object-ui/plugin-form type-check(echoes 'tsc --noEmit && tsc -p tsconfig.test.json'): VERDICT command-exit 0.pnpm exec vitest run --maxWorkers=2 packages/plugin-form/: VERDICT command-exit 0, 'Test Files 163 passed (163) / Tests 1889 passed | 1 skipped (1890)'. (4) 21 manifest-reading or source-text-reading files (selected by import AND by readFileSync / file-name grep): the new pin, registry-inputs-spec-parity, sdui-manifest-build-11403, html-tier-manifest, html-tier-code-element-10756, htmlTierDataSourceInputDeclaration-6678, sdui-intrinsics-compile-11075, ga-honoured-inputs-author-reach, component-input-union-specimens, element-data-source-input-injection, i18nLabelInputsManifest-10993, masterDetailForm/objectForm manifest tests, public-block-binding-reach, public-contract, record-block-record-reach, filterContextTokensSweep-10666, element-data-source-objectname-waiver-11117 (reads data-source.md), registered-types-validate-ratchet-10859, page-block-path. Result: VERDICT command-exit 0, 'Test Files 21 passed (21) / Tests 614 passed (614)'. (5) ABLATION on the committed fix, via objectstack scripts/ablation-replace.mjs in WRAP mode, put required: true back. Disk proof: anchor 1 → 0, replacement 0 → 1, blob e9b208727dd7 → 2591aef44b45. Result: rows 1, 2, 5 red ('3 failed | 2 passed'), each with missing-required-prop childObject; controls 3 and 4 stayed green. Restore: blob e9b208727dd7 == HEAD, git diff HEAD empty. No build is needed: vitest aliases @object-ui/plugin-form to packages/plugin-form/src. The first ablation attempt was refused by the tool (its anchor count moved from 1 to 1, a drop of 0, because the replacement contained the anchor). It restored and measured nothing, and was redone with a 2-line anchor. (6) Accept-set probe, a throwaway untracked test deleted after the run. Shipped manifest, before = required restored via ablation-replace, after = head. Bound node: ok false + 1 error → ok true, [] (binding recorded both). Neither node: ok false → ok true, []. childObject node: ok true both. sdui-intrinsics.d.ts: 'childObject: string' → 'childObject?: string'. sdui-blocks.md required column: 'childObject, relationshipField, columns' → 'relationshipField, columns'. Two earlier probe attempts were queue-timeout 99 (NOT MEASURED). One printed nothing because console output is suppressed in that project, so it was re-run writing to a file. (7) eslint narrowed proof: --no-inline-config --format json over the 4 touched ts/tsx files gave 4 files, 0 errors. Warnings per file are equal at base (git show BASE via --stdin) and head: 22/18/4. Invariance: no project/projectService in eslint.config.js, and no eslint-rules/ rule reads the disk.","mcp_calls": "0",
"api_writes": "3 REST writes, all through the scripts/pm fleet-write relay as objectstack-fleet[bot]: (1) pr_create, i.e. POST /repos/objectstack-ai/objectui/pulls with draft forced (relay run 37190892816; read-back 8633 bytes sent, 8633 stored, identical). (2) label-write --assign os-zhuang, i.e. POST /repos//issues/11604/assignees (relay run 37190927482; read-back MATCHES, labels untouched). (3) this os-dev-report comment, i.e. POST /repos//issues/11569/comments via post-stamped. Each relay hop is one POST /repos/objectstack-ai/objectstack/dispatches. Also 2 git pushes of the branch (empty probe push, then 448bac5), which are not REST.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: public door, measured. A throwaway probe compiled against the shipped sdui.manifest.json (buildArtifacts over apps/console/dev/manifest-registry.ts). For each of
object-grid,object-kanbanandobject-metric, a node with only dataSource {object: 'account'} gets ok false with [error, missing-required-prop, objectName]. All three @objectstack/spec 17.6.0 ComponentPropsMap rows make objectName optional 'because the component-leveldataSourcebinding can supply the object instead' (ObjectGridPropsSchema, ObjectKanbanPropsSchema, ObjectMetricPropsSchema describe text, read from the installed spec dist). The registrations still declare { name: 'objectName', required: true }: plugin-grid index.tsx, plugin-kanban index.tsx, plugin-dashboard index.tsx (object-metric). This is the same defect class as objectui#11569: fold it into one family closing card, not single-point cards. The same probe also refuses boundlist-view,object-chartandobject-pivotwithout objectName. Those three have no ComponentPropsMap row, so the contract there is objectui's own content/docs/guide/data-source.md sentence 'a node bound this way needs noobjectNameof its own' (plus, for list-view, the safeValidateSchema record-source rule). Seam: spec:ComponentPropsMap['object-grid'|'object-kanban'|'object-metric'].objectName (optional) → runtime: sdui-parser validateTree missing-required-prop via each registration's inputs. Precedents: objectui#10392, the calendar sibling of objectui#7470 (map/gantt), and objectui#10909. Dedupe words:objectName required dataSource binding page compile·missing-required-prop objectName object-grid object-kanban object-metric·gate-wrapped registration required vs spec row optional.","carrier: 承接者:无 · noted, not filed.
LineItemsPanelSchema.childObject(the plugin-form panel's TypeScript prop type) staysstring, not optional, while the spec row and the registration leave it optional. It is a React prop type, not stored metadata: the gate fills it before the panel reads it, and the panel guards undefined. It is in the PR's Acceptance notes only."],
"gates": [
{
"command": "pnpm --filter '@object-ui/plugin-form^...' build",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0 (Scope: 12 of 47 workspace projects)"
},
{
"command": "pnpm --filter @object-ui/plugin-form type-check",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0"
},
{
"command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-form/ (root form of
pnpm --filter @object-ui/plugin-form test)","exit": 0,
"verdict": "Test Files 163 passed (163); Tests 1889 passed | 1 skipped (1890)"
},
{
"command": "pnpm exec vitest run --maxWorkers=2 (21 manifest/source-text readers incl. registry-inputs-spec-parity.test.ts and the new pin)",
"exit": 0,
"verdict": "Test Files 21 passed (21); Tests 614 passed (614)"
},
{
"command": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"exit": 0,
"verdict": "No changeset declares a
majorbump."},
{
"command": "node scripts/check-changeset-overwrite.mjs",
"exit": 0,
"verdict": "No pre-existing changeset was modified or deleted."
},
{
"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": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 7496 tracked text file(s); skipped 85 binary)."
},
{
"command": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only → exit 0"
},
{
"command": "pnpm check:handler-key-reads",
"exit": 0,
"verdict": "OK 151 arm(s), 183 registration(s) ... every judged read is a declared member of its arm."
},
{
"command": "pnpm docs:check-links",
"exit": 0,
"verdict": "Links are valid across 17 scan roots."
},
{
"command": "pnpm check:doc-types",
"exit": 0,
"verdict": "Every documented component type is registered."
},
{
"command": "pnpm check:doc-fences",
"exit": 0,
"verdict": "every TypeScript block in 227 document(s) is fenced ts/tsx/typescript"
},
{
"command": "pnpm check:doc-example-ids",
"exit": 0,
"verdict": "415 real reference(s) all resolve in the catalog registry."
},
{
"command": "pnpm check:element-data-source-declaration",
"exit": 0,
"verdict": "OK — 14 gate-consuming file(s) checked"
},
{
"command": "pnpm check:test-path-roots",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"command": "node scripts/check-vi-mock-override-shape.mjs",
"exit": 0,
"verdict": "check-vi-mock-override-shape: OK"
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (6 changed paths)",
"exit": 0,
"verdict": "NOT GOVERNED — 6 path(s) checked against 5 governed surface(s); none matched."
},
{
"command": "pnpm check:doc-snippets",
"exit": 2,
"verdict": "NOT MEASURED: PRECONDITION NOT MET (unbuilt packages); the docs edit adds no code fence; declared to CI"
},
{
"command": "pnpm check:doc-examples",
"exit": 2,
"verdict": "NOT MEASURED: THE GATE COULD NOT RUN (unbuilt packages); declared to CI"
},
{
"command": "@object-ui/console type-check",
"exit": null,
"verdict": "NOT MEASURED: needs the whole console closure built; a scoped tsc over the new test file listed it in the program with 0 errors in it (36 TS2307/TS2882 unresolved-module errors, all in dev/manifest-registry.ts and src/register-plugins.ts); declared to CI"
},
{
"command": "CI on PR #11604 at 448bac5",
"exit": null,
"verdict": "in_progress at report time: 21 success, 3 skipped, 18 in_progress of 42 check runs"
}
],
"files_changed": [
"packages/plugin-form/src/index.tsx",
"packages/plugin-form/src/LineItemsPanel.tsx",
"packages/plugin-form/src/LineItemsPanel.childObjectDecline.test.tsx",
"apps/console/src/tests/line-items-bound-child-object-11569.test.ts",
"content/docs/guide/data-source.md",
".changeset/11569-line-items-child-object-optional.md"
],
"deviations": [
"Pin location: the new pin lives in apps/console, not plugin-form. It judges against the manifest the console actually ships (the save gate's input), and it avoids adding @object-ui/sdui-parser as a new plugin-form devDependency (check-phantom-dependencies would otherwise flag the test import, and pnpm-lock.yaml would change). The claim named 'new pins' without a location.",
"File surface beyond the claim list: LineItemsPanel.tsx and LineItemsPanel.childObjectDecline.test.tsx carry comment-only rewrites of two comments this change made false (they said childObject is required: true on the registry entry). content/docs/guide/data-source.md gains one prose sentence (AGENTS.md #2, docs-driven). All are named in the PR body.",
"Hypothesis 1: the hypothesis used getAllConfigs(). I measured against the shipped sdui.manifest.json, which emitSduiManifest writes from getPublicConfigs() after loading dev/manifest-registry.ts. That file is the one a host registers as the page-save gate manifest. The refusal reproduced identically.",
"Hypothesis 4 falsified: registry-inputs-spec-parity.test.ts does not compare requiredness (0 reads of an input's
required; control: it reads input.of and input.type). It books nothing and is unchanged.","Gate lead
pnpm --filter @object-ui/plugin-form testwas run in its repo-root formpnpm exec vitest run --maxWorkers=2 packages/plugin-form/. Per objectui AGENTS.md this is the same root config, with a worker cap for the shared box.","Commit trailer: the commit carries objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude). The harness reminder asked for a model-named Co-Authored-By line; the repo rule takes precedence.",
"Declared narrowings (CI runs the full farm): the full @object-ui/console type-check, check:doc-snippets and check:doc-examples are NOT MEASURED locally, for the reasons in gates."
],
"line_budget": "n/a (no skills/** touched)"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Seat review of PR objectui#11604 at head
448bac5da(dev report5978370413): content ACCEPT;Clause-②: yes, so the at-tier contract review runs before readydomain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-04T09:09Z. Reviewed against GitHub, not the report.main. The first line isFixes #11569, with no other closing keyword.Clause-②: yesis at line start. 6 files, +174 / −17.check-governed-merges: NOT governed. The PR assignee isos-zhuang.5972410418, carried out:ComponentInput/ManifestInputcarry only a booleanrequired, andbinding: 'object'marks an object-naming input, not requiredness. So no "one of these is required" form exists, andchildObjectdropsrequired: true.packages/typesis untouched, which honours objectui#8347's hold.relationshipFieldandcolumnsstay required.registry-inputs-spec-parity.test.tsreads norequired, so it books nothing and is unchanged.apps/console/src/__tests__/line-items-bound-child-object-11569.test.tsjudges against the manifest the console ships (sdui.manifest.json, the save gate's input).missing-required-propat error).required: truerestore: rows 1, 2 and 5 red, controls green, restored by blob hash.LineItemsPanel.childObjectDeclinekeeps the neither-node's runtime hint.plugin-formpackage is green: 163 files, 1,889 tests. So are 21 manifest and source-text readers: 614 tests.childObjectgoes fromok: falsetook: true;ok: falsetook: true, and the panel's config hint is the answer there;sdui-intrinsics.d.tsgoes fromchildObject: stringtochildObject?: string;sdui-blocks.md's required column dropschildObject.apps/console(notplugin-form) is accepted: it judges the shipped manifest, and avoids a newsdui-parserdevDependency inplugin-form.LineItemsPanel.tsxand its test (two comments this change made false), and one prose sentence incontent/docs/guide/data-source.md, are accepted. They are named in the PR.object-grid,object-kanbanandobject-metric(spec rows waiveobjectName), pluslist-view,object-chartandobject-pivot(by the binding doc), still declareobjectNamerequired. The page compile refuses each bound node. This is this card's family's second occurrence ⇒ filed registrations still declareobjectNamerequired where thedataSourcebinding can supply it, so the page compile refuses bound object-grid / object-kanban / object-metric nodes (the objectui#11569 family's closing card) #11605 as the family's closing card, with an enumeration pin.LineItemsPanelSchema.childObjectstays typedstring. It is a React prop the gate fills ⇒ Acceptance notes.needs:contract-reviewgoes on the PR now. An isolated at-tier review runs on this head.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Seat answer to the at-tier record
5978497549(FAIL on ② only) ⇒ regrade the changeset tominor; the contradiction was the claim'sdomain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-04T09:25Z.AGENTS.md, Post-Task Checklist item 3, reads: "The declaration isClause-②: yes|no…:yestakes at leastminor". objectui's closest precedent agrees:element:number'sobjectno longerrequired(objectui#10909, PR objectui#10944) declaredClause-②: yes (widening)and shippedminor. This seat's claim5977893924pairedClause-②: yeswith "one@object-ui/plugin-formpatchchangeset", and the dev executed the claim as written..changeset/11569-line-items-child-object-optional.mdgrades@object-ui/plugin-formminor.**Clause-②: yes (widening)**banner the repository's recent minors carry.needs:contract-reviewstays on until a PASS is on record.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{
"issue": 11569,
"status": "done",
"round": "patch round 1 (contract review 5978497549 FAIL on ② only; seat answer 5978504784)",
"branch": "claude/issue-11569-line-items-childobject",
"pr": "#11604",
"head": "84ee3bec8d09b44bab9c3814694f7baebd51a36c",
"session": "session_01FjqrwXPfSMkSfkKYDSRkN2 (mode:subagent; the parent PM session id, as the claim names it)",
"premise_still_valid": true,
"summary": "Patch round: the changeset is regraded and nothing else moves.
.changeset/11569-line-items-child-object-optional.mdnow grades'@object-ui/plugin-form': minor, because aClause-②: yeswidening takes at least minor, as the objectui#10909 / PR objectui#10944 precedent shipped. Its widening paragraph now opens with the**Clause-②: yes (widening)**banner, spelled as on main (packages/components/CHANGELOG.md, the element:number entry). Commit 84ee3be is pushed on top of 448bac5 and touches only that file (2 lines). All six named changeset gates exit 0 on 84ee3be. The PR body names the bump level, so a replacement body is carried inpr_body_updatefor the seat to write. Round 0 still holds unchanged for the fix itself: the registration dropsrequired: trueonchildObjectwith no new vocabulary, the pin was red first, ablated red, and restored by blob hash.","tests": "Round 1 at 84ee3be (changeset-only commit, so code is byte-identical to 448bac5 and the round-0 test, build and type-check runs stand). Changeset gates re-run on 84ee3be: check-changeset-presence, check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims and check:pending-changeset-literals each exit 0; check:control-bytes and check:new-line-citations also exit 0 (verdict lines in gates). Round 0, at 448bac5: All at head 448bac5. (1) REPRODUCE: the new pin apps/console/src/tests/line-items-bound-child-object-11569.test.ts ran on unfixed source: 4 failed / 1 passed. Row 2 received [error, missing-required-prop, 'record:line_items is missing required prop childObject']. Row 4 was then re-cut into a true before/after control. (2) GREEN: the pin plus LineItemsPanel.childObjectDecline.test.tsx: 'Test Files 2 passed (2) / Tests 10 passed (10)'. (3)
pnpm --filter '@object-ui/plugin-form^...' build: VERDICT command-exit 0 (Scope: 12 of 47).pnpm --filter @object-ui/plugin-form type-check(echoes 'tsc --noEmit && tsc -p tsconfig.test.json'): VERDICT command-exit 0.pnpm exec vitest run --maxWorkers=2 packages/plugin-form/: VERDICT command-exit 0, 'Test Files 163 passed (163) / Tests 1889 passed | 1 skipped (1890)'. (4) 21 manifest-reading or source-text-reading files (selected by import AND by readFileSync / file-name grep): the new pin, registry-inputs-spec-parity, sdui-manifest-build-11403, html-tier-manifest, html-tier-code-element-10756, htmlTierDataSourceInputDeclaration-6678, sdui-intrinsics-compile-11075, ga-honoured-inputs-author-reach, component-input-union-specimens, element-data-source-input-injection, i18nLabelInputsManifest-10993, masterDetailForm/objectForm manifest tests, public-block-binding-reach, public-contract, record-block-record-reach, filterContextTokensSweep-10666, element-data-source-objectname-waiver-11117 (reads data-source.md), registered-types-validate-ratchet-10859, page-block-path. Result: VERDICT command-exit 0, 'Test Files 21 passed (21) / Tests 614 passed (614)'. (5) ABLATION on the committed fix, via objectstack scripts/ablation-replace.mjs in WRAP mode, put required: true back. Disk proof: anchor 1 → 0, replacement 0 → 1, blob e9b208727dd7 → 2591aef44b45. Result: rows 1, 2, 5 red ('3 failed | 2 passed'), each with missing-required-prop childObject; controls 3 and 4 stayed green. Restore: blob e9b208727dd7 == HEAD, git diff HEAD empty. No build is needed: vitest aliases @object-ui/plugin-form to packages/plugin-form/src. The first ablation attempt was refused by the tool (its anchor count moved from 1 to 1, a drop of 0, because the replacement contained the anchor). It restored and measured nothing, and was redone with a 2-line anchor. (6) Accept-set probe, a throwaway untracked test deleted after the run. Shipped manifest, before = required restored via ablation-replace, after = head. Bound node: ok false + 1 error → ok true, [] (binding recorded both). Neither node: ok false → ok true, []. childObject node: ok true both. sdui-intrinsics.d.ts: 'childObject: string' → 'childObject?: string'. sdui-blocks.md required column: 'childObject, relationshipField, columns' → 'relationshipField, columns'. Two earlier probe attempts were queue-timeout 99 (NOT MEASURED). One printed nothing because console output is suppressed in that project, so it was re-run writing to a file. (7) eslint narrowed proof: --no-inline-config --format json over the 4 touched ts/tsx files gave 4 files, 0 errors. Warnings per file are equal at base (git show BASE via --stdin) and head: 22/18/4. Invariance: no project/projectService in eslint.config.js, and no eslint-rules/ rule reads the disk.","mcp_calls": "0",
"api_writes": "4 REST writes in total, all through the scripts/pm fleet-write relay as objectstack-fleet[bot]. Round 0: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (run 37190892816). (2) label-write --assign os-zhuang, POST /repos//issues/11604/assignees (run 37190927482). (3) the round-0 os-dev-report comment 5978370413, POST /repos//issues/11569/comments. Round 1: (4) this os-dev-report comment, POST /repos//issues/11569/comments via post-stamped. Each relay hop is one POST /repos/objectstack-ai/objectstack/dispatches. There was no PR edit: the replacement body is in pr_body_update for the seat. Also 3 git pushes of the branch (empty probe, 448bac5, 84ee3be), which are not REST.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: public door, measured. A throwaway probe compiled against the shipped sdui.manifest.json (buildArtifacts over apps/console/dev/manifest-registry.ts). For each of
object-grid,object-kanbanandobject-metric, a node with only dataSource {object: 'account'} gets ok false with [error, missing-required-prop, objectName]. All three @objectstack/spec 17.6.0 ComponentPropsMap rows make objectName optional 'because the component-leveldataSourcebinding can supply the object instead' (ObjectGridPropsSchema, ObjectKanbanPropsSchema, ObjectMetricPropsSchema describe text, read from the installed spec dist). The registrations still declare { name: 'objectName', required: true }: plugin-grid index.tsx, plugin-kanban index.tsx, plugin-dashboard index.tsx (object-metric). This is the same defect class as objectui#11569: fold it into one family closing card, not single-point cards. The same probe also refuses boundlist-view,object-chartandobject-pivotwithout objectName. Those three have no ComponentPropsMap row, so the contract there is objectui's own content/docs/guide/data-source.md sentence 'a node bound this way needs noobjectNameof its own' (plus, for list-view, the safeValidateSchema record-source rule). Seam: spec:ComponentPropsMap['object-grid'|'object-kanban'|'object-metric'].objectName (optional) → runtime: sdui-parser validateTree missing-required-prop via each registration's inputs. Precedents: objectui#10392, the calendar sibling of objectui#7470 (map/gantt), and objectui#10909. Dedupe words:objectName required dataSource binding page compile·missing-required-prop objectName object-grid object-kanban object-metric·gate-wrapped registration required vs spec row optional. Status: the seat has filed this as objectui#11605 (per review 5978497549 ③.4), so nothing more is owed here.","carrier: 承接者:无 · noted, not filed.
LineItemsPanelSchema.childObject(the plugin-form panel's TypeScript prop type) staysstring, not optional, while the spec row and the registration leave it optional. It is a React prop type, not stored metadata: the gate fills it before the panel reads it, and the panel guards undefined. It is in the PR's Acceptance notes only."],
"gates": [
{
"command": "node scripts/check-changeset-presence.mjs (84ee3be)",
"exit": 0,
"verdict": "4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s): .changeset/11569-line-items-child-object-optional.md."
},
{
"command": "node scripts/check-changeset-no-major.mjs (84ee3be)",
"exit": 0,
"verdict": "No changeset declares a
majorbump."},
{
"command": "node scripts/check-changeset-overwrite.mjs (84ee3be)",
"exit": 0,
"verdict": "No pre-existing changeset was modified or deleted."
},
{
"command": "node scripts/check-changeset-fixed.mjs (84ee3be)",
"exit": 0,
"verdict": "All workspace packages are in the changeset fixed group. / privatePackages declared: version=true, tag=false."
},
{
"command": "pnpm check:changeset-claims (84ee3be)",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"command": "pnpm check:pending-changeset-literals (84ee3be)",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "pnpm check:control-bytes (84ee3be)",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 7496 tracked text file(s); skipped 85 binary)."
},
{
"command": "pnpm check:new-line-citations (84ee3be)",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only → exit 0"
},
{
"command": "CI on PR #11604 at 84ee3be",
"exit": null,
"verdict": "in_progress at report time: 18 success, 3 skipped, 21 in_progress of 42 check runs"
},
{
"command": "pnpm --filter '@object-ui/plugin-form^...' build (round 0, 448bac5)",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0 (Scope: 12 of 47 workspace projects)"
},
{
"command": "pnpm --filter @object-ui/plugin-form type-check (round 0, 448bac5)",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0"
},
{
"command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-form/ (root form of
pnpm --filter @object-ui/plugin-form test) (round 0, 448bac5)","exit": 0,
"verdict": "Test Files 163 passed (163); Tests 1889 passed | 1 skipped (1890)"
},
{
"command": "pnpm exec vitest run --maxWorkers=2 (21 manifest/source-text readers incl. registry-inputs-spec-parity.test.ts and the new pin) (round 0, 448bac5)",
"exit": 0,
"verdict": "Test Files 21 passed (21); Tests 614 passed (614)"
},
{
"command": "node scripts/check-changeset-presence.mjs (round 0, 448bac5)",
"exit": 0,
"verdict": "4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs (round 0, 448bac5)",
"exit": 0,
"verdict": "No changeset declares a
majorbump."},
{
"command": "node scripts/check-changeset-overwrite.mjs (round 0, 448bac5)",
"exit": 0,
"verdict": "No pre-existing changeset was modified or deleted."
},
{
"command": "pnpm check:changeset-claims (round 0, 448bac5)",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"command": "pnpm check:pending-changeset-literals (round 0, 448bac5)",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "pnpm check:control-bytes (round 0, 448bac5)",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 7496 tracked text file(s); skipped 85 binary)."
},
{
"command": "pnpm check:new-line-citations (round 0, 448bac5)",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only → exit 0"
},
{
"command": "pnpm check:handler-key-reads (round 0, 448bac5)",
"exit": 0,
"verdict": "OK 151 arm(s), 183 registration(s) ... every judged read is a declared member of its arm."
},
{
"command": "pnpm docs:check-links (round 0, 448bac5)",
"exit": 0,
"verdict": "Links are valid across 17 scan roots."
},
{
"command": "pnpm check:doc-types (round 0, 448bac5)",
"exit": 0,
"verdict": "Every documented component type is registered."
},
{
"command": "pnpm check:doc-fences (round 0, 448bac5)",
"exit": 0,
"verdict": "every TypeScript block in 227 document(s) is fenced ts/tsx/typescript"
},
{
"command": "pnpm check:doc-example-ids (round 0, 448bac5)",
"exit": 0,
"verdict": "415 real reference(s) all resolve in the catalog registry."
},
{
"command": "pnpm check:element-data-source-declaration (round 0, 448bac5)",
"exit": 0,
"verdict": "OK — 14 gate-consuming file(s) checked"
},
{
"command": "pnpm check:test-path-roots (round 0, 448bac5)",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"command": "node scripts/check-vi-mock-override-shape.mjs (round 0, 448bac5)",
"exit": 0,
"verdict": "check-vi-mock-override-shape: OK"
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (6 changed paths) (round 0, 448bac5)",
"exit": 0,
"verdict": "NOT GOVERNED — 6 path(s) checked against 5 governed surface(s); none matched."
},
{
"command": "pnpm check:doc-snippets (round 0, 448bac5)",
"exit": 2,
"verdict": "NOT MEASURED: PRECONDITION NOT MET (unbuilt packages); the docs edit adds no code fence; declared to CI"
},
{
"command": "pnpm check:doc-examples (round 0, 448bac5)",
"exit": 2,
"verdict": "NOT MEASURED: THE GATE COULD NOT RUN (unbuilt packages); declared to CI"
},
{
"command": "@object-ui/console type-check (round 0, 448bac5)",
"exit": null,
"verdict": "NOT MEASURED: needs the whole console closure built; a scoped tsc over the new test file listed it in the program with 0 errors in it (36 TS2307/TS2882 unresolved-module errors, all in dev/manifest-registry.ts and src/register-plugins.ts); declared to CI"
}
],
"files_changed": [
"packages/plugin-form/src/index.tsx",
"packages/plugin-form/src/LineItemsPanel.tsx",
"packages/plugin-form/src/LineItemsPanel.childObjectDecline.test.tsx",
"apps/console/src/tests/line-items-bound-child-object-11569.test.ts",
"content/docs/guide/data-source.md",
".changeset/11569-line-items-child-object-optional.md"
],
"files_changed_this_round": [
".changeset/11569-line-items-child-object-optional.md"
],
"deviations": [
"Round 1: the banner replaces the paragraph's old
**Behaviour change.**label. It now reads**Clause-②: yes (widening)** — a record:line_items node that names ..., following the em-dash form of the element:number minor on main. The rest of the paragraph is unchanged. Keeping both labels would have stacked two bold openers, so this is the one wording move beyond the grade.","Round 1: the round-0 worktree had already been removed at cleanup. It was re-added on the same local branch after checking that the remote branch head equalled 448bac5, then pnpm install was run (no lockfile change).",
"Pin location: the new pin lives in apps/console, not plugin-form. It judges against the manifest the console actually ships (the save gate's input), and it avoids adding @object-ui/sdui-parser as a new plugin-form devDependency (check-phantom-dependencies would otherwise flag the test import, and pnpm-lock.yaml would change). The claim named 'new pins' without a location.",
"File surface beyond the claim list: LineItemsPanel.tsx and LineItemsPanel.childObjectDecline.test.tsx carry comment-only rewrites of two comments this change made false (they said childObject is required: true on the registry entry). content/docs/guide/data-source.md gains one prose sentence (AGENTS.md #2, docs-driven). All are named in the PR body.",
"Hypothesis 1: the hypothesis used getAllConfigs(). I measured against the shipped sdui.manifest.json, which emitSduiManifest writes from getPublicConfigs() after loading dev/manifest-registry.ts. That file is the one a host registers as the page-save gate manifest. The refusal reproduced identically.",
"Hypothesis 4 falsified: registry-inputs-spec-parity.test.ts does not compare requiredness (0 reads of an input's
required; control: it reads input.of and input.type). It books nothing and is unchanged.","Gate lead
pnpm --filter @object-ui/plugin-form testwas run in its repo-root formpnpm exec vitest run --maxWorkers=2 packages/plugin-form/. Per objectui AGENTS.md this is the same root config, with a worker cap for the shared box.","Commit trailer: the commit carries objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude). The harness reminder asked for a model-named Co-Authored-By line; the repo rule takes precedence.",
"Declared narrowings (CI runs the full farm): the full @object-ui/console type-check, check:doc-snippets and check:doc-examples are NOT MEASURED locally, for the reasons in gates."
],
"pr_body_update": "Fixes #11569\nClause-②: yes\n\n## What changes\n\nThe
record:line_itemsregistration in@object-ui/plugin-formno longer declareschildObjectwithrequired: true. The input now publishes adescription: the node'sdataSourcebinding can name the object instead (dataSource.objectlands on this key and outranks an authored value), and a node with neither shows the panel's configuration hint and loads nothing.\n\nWhy:@objectstack/spec17.6.0'sComponentPropsMap['record:line_items']leaveschildObjectoptional "because the component-leveldataSourcebinding can supply the object instead", and the renderer agrees (RECORD_LINE_ITEMS_DATA_SOURCEmaps the binding'sobjectontochildObject). The page compile (compile()in@object-ui/sdui-parser, whoseokis the save gate) reads the registration, so it refused a bound node that the row, the zod faces and the runtime all accept.\n\n## The vocabulary question, measured\n\nThe manifest has no "one of these is required" form, so per the triage rulingrequired: trueis dropped and nothing is added:\n\n-ComponentInput(@object-ui/types,base.ts) declaresname,type,of,required(a boolean),enumanddescription, plus retirement tombstones.\n-ManifestInput(@object-ui/sdui-parser,types.ts) adds the framework-setbinding: 'object'marker. It says an input NAMES an object and carries no requiredness.\n-validateTree's only requiredness check isinput.required && !(input.name in node).\n\npackages/typesis not edited. The same shape already landed in this repo:element:number'sobject(objectui#10909), and theobjectNameinputs ofobject-calendar,object-gantt,object-mapandobject-timeline, each droppedrequiredand gained a description that names the binding.\n\n## Accept-set changes (for the contract review)\n\nMeasured against the manifest the console ships (buildArtifactsoverdev/manifest-registry.ts). "Before" is this head withrequired: trueput back throughablation-replace.mjs; "after" is this head.\n\n| node | before | after |\n|---|---|---|\n|record:line_itemswithdataSource.object,relationshipField,columns, nochildObject|ok: false: one error,missing-required-propnamingchildObject|ok: true, no diagnostics. ThedataSourcebinding site is recorded in both runs |\n|record:line_itemswithrelationshipFieldandcolumns, and neitherchildObjectnordataSource|ok: false: the same error |ok: true, no diagnostics. The ruling leaves this node to the runtime: the panel shows the configuration hint namingchildObjectand fetches nothing.LineItemsPanel.childObjectDecline.test.tsxpins the hint, unchanged and green |\n|record:line_itemswithchildObject,relationshipFieldandcolumns|ok: true|ok: true(control) |\n\nGenerated artifacts that move with it (same generator, same runs):\n\n-sdui.manifest.json, entryrecord:line_items, inputchildObject:required: trueremoved,descriptionadded.\n-sdui-intrinsics.d.ts(the typed JSX face):childObject: stringbecomeschildObject?: string.\n-sdui-blocks.md, the required-props column forrecord:line_items:childObject, relationshipField, columnsbecomesrelationshipField, columns.\n\nUnchanged:relationshipFieldandcolumnsstay required. The zod faces (objectui validate), the spec row and the renderer are not touched.\n\n## registry-inputs-spec-parity\n\napps/console/src/__tests__/registry-inputs-spec-parity.test.tsdoes not compare requiredness, so nothing in it records this difference and the file is unchanged. Evidence: the file never reads an input'srequired, and it does readinput.ofandinput.type(the control). It is green on this head.\n\n## Pins\n\nNew:apps/console/src/__tests__/line-items-bound-child-object-11569.test.ts. It judges against the shippedsdui.manifest.json(written byemitSduiManifestand read back):\n\n1. The published entry declareschildObjectas not required, with a description that namesdataSourceanddataSource.object.relationshipFieldandcolumnsstay required.\n2. The bound node compilesokwith no diagnostic, and the binding is recorded.\n3. Control: thechildObjectnode compilesok.\n4. Control: a node that nameschildObjectbut has norelationshipFieldis refused with exactly onemissing-required-prop. This row reads the same before and after the fix.\n5. The neither node draws no compile diagnostic aboutchildObject.\n\nReproduced first: before the fix, rows 1, 2 and 5 were red, each withmissing-required-propnamingchildObjectat error severity.\n\nAblation, run on the committed fix:ablation-replace.mjsputrequired: trueback (anchor hit once, blobe9b208727dd7became2591aef44b45). Rows 1, 2 and 5 turned red (3 failed, 2 passed). The restore is proven by blob hash:e9b208727dd7equals HEAD andgit diff HEADis empty. On resolution: the console project aliases@object-ui/plugin-formtopackages/plugin-form/src, so the mutation reaches the test without a build. One first attempt was refused by the tool before any test ran, because its replacement contained its own anchor. It restored to HEAD and measured nothing.\n\n## Other edits\n\n-LineItemsPanel.tsxandLineItemsPanel.childObjectDecline.test.tsx: comment-only. Two comments saidchildObjectwas declaredrequired: trueon the registry entry and that the block had no spec schema. They now state the current facts.\n-content/docs/guide/data-source.md: one prose sentence, no code fence. A boundrecord:line_itemsnode needs nochildObjectand the page compile accepts it. A node with neither shows the configuration hint.\n-.changeset/11569-line-items-child-object-optional.md:@object-ui/plugin-formminor. AClause-②: yeswidening takes at leastminor, which matches the objectui#10909 landing (PR objectui#10944). It was first gradedpatchand regraded at84ee3beafter the at-tier contract review5978497549. Its widening paragraph opens with the**Clause-②: yes (widening)**banner.\n\n## Verification (head84ee3be)\n\n84ee3bechanges only the changeset (the grade and the banner). The test, build and type-check runs below were taken at448bac5, whose code is identical. The changeset gates were re-run at84ee3be:check-changeset-presence,check-changeset-no-major,check-changeset-overwrite,check-changeset-fixed,check:changeset-claims,check:pending-changeset-literals,check:control-bytesandcheck:new-line-citationseach exit 0.\n\n-pnpm --filter '@object-ui/plugin-form^...' build: exit 0 (12 of 47 projects).\n-pnpm --filter @object-ui/plugin-form type-check: exit 0 (tsc --noEmit && tsc -p tsconfig.test.json).\n-pnpm exec vitest run packages/plugin-form/: exit 0.Test Files 163 passed (163),Tests 1889 passed | 1 skipped (1890).\n- 21 files that read the registry manifest or the edited docs: exit 0,Test Files 21 passed (21),Tests 614 passed (614). They include the new pin,registry-inputs-spec-parity,sdui-manifest-build-11403,html-tier-manifest,sdui-intrinsics-compile-11075,public-contract,record-block-record-reach,element-data-source-objectname-waiver-11117(readsdata-source.md) andregistered-types-validate-ratchet-10859.\n-check-changeset-presence,check-changeset-no-major,check-changeset-overwrite,check:changeset-claims,check:pending-changeset-literals,check:control-bytes,check:new-line-citations(0 new citation(s)),check:handler-key-reads,docs:check-links,check:doc-types,check:doc-fences,check:doc-example-ids,check:element-data-source-declaration,check:test-path-rootsandcheck-vi-mock-override-shape: each exit 0.\n-check-governed-queue-guard --testover the six paths:NOT GOVERNED.\n- eslint over the 4 touched ts/tsx files (--no-inline-config --format json): 4 files, 0 errors. The warning count per file is equal at base and head (22, 18, 4). The config has no type-aware linting (noproject/projectService), and no custom rule ineslint-rules/reads the disk, so this diff cannot change the result for an untouched file.\n- NOT MEASURED, left to CI:\n -check:doc-snippetsandcheck:doc-examplesstopped atPRECONDITION NOT MET(exit 2) because the packages are unbuilt. The docs edit adds no code fence.\n - The full@object-ui/consoletype-check needs the whole console closure built. A scopedtscover the new test file (console tsconfig) shows the file in the program with 0 errors in it. All 36 errors it printed are module-resolution errors (TS2307 / TS2882) for unbuilt packages, indev/manifest-registry.tsandsrc/register-plugins.ts.\n\n## Acceptance notes\n\n-LineItemsPanelSchema.childObject(the panel component's TypeScript prop type) is stillstring, not optional. It is a React prop type, not stored metadata: the gate fills it before the panel reads it, and the panel guards theundefinedcase. Recorded only. Carrier: none.\n- The same defect class on sibling gate-wrapped blocks is listed in the dev report for the seat to file. Not touched here.\n\nImplemented by the os-dev run under sessionhttps://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2, for the claim on the card.\n\n---\n_Generated by Claude Code_\n","line_budget": "n/a (no skills/** touched)"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Landed and verified by content: closed
completedby PR objectui#11604 ·domain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-04T10:09Z.The merge: PR objectui#11604 went through the merge queue to
mainas902ebabat 2026-10-04T10:09Z.5978394943.5978691275at head84ee3be, after FAIL5978497549at448bac5. Label removal provenance:5978698968.Content check of
packages/plugin-form/src/index.tsxonmain902ebabagainst its first parent278d244:main{ name: 'childObject', type: 'string', required: true }Not required: the node…onchildObjectrelationshipFieldstillrequired: true(control)The changeset
11569-line-items-child-object-optional.mdis in the tree, graded'@object-ui/plugin-form': minor, with the**Clause-②: yes (widening)** —banner. The pinapps/console/src/__tests__/line-items-bound-child-object-11569.test.tsis in the tree too. The diff is exactly the reviewed 6 files, +174 / −17.No other card closed in that window.
pm:dispatchedis removed in the same act.domain:ui,area:records, the type and the priority stay.Carried on: the
objectNamefamily (object-grid,object-kanban,object-metric,list-view,object-chart,object-pivot) is objectui#11605, the closing card. It waits for triage to grade it and to answer the one-of-required vocabulary question5978510533.Generated by Claude Code
fix(plugin-form): record:line_items stops requiring childObject, so t…