Skip to content

fix(plugin-form): record:line_items stops requiring childObject, so the page compile accepts a dataSource-bound node (objectui#11569) - #11604

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-11569-line-items-childobject
Oct 4, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-11569-line-items-childobject

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #11569
Clause-②: yes

What changes

The record:line_items registration in @object-ui/plugin-form no longer declares childObject with required: true. The input now publishes a description: the node's dataSource binding can name the object instead (dataSource.object lands on this key and outranks an authored value), and a node with neither shows the panel's configuration hint and loads nothing.

Why: @objectstack/spec 17.6.0's ComponentPropsMap['record:line_items'] leaves childObject optional "because the component-level dataSource binding can supply the object instead", and the renderer agrees (RECORD_LINE_ITEMS_DATA_SOURCE maps the binding's object onto childObject). The page compile (compile() in @object-ui/sdui-parser, whose ok is the save gate) reads the registration, so it refused a bound node that the row, the zod faces and the runtime all accept.

The vocabulary question, measured

The manifest has no "one of these is required" form, so per the triage ruling required: true is dropped and nothing is added:

  • ComponentInput (@object-ui/types, base.ts) declares name, type, of, required (a boolean), enum and description, plus retirement tombstones.
  • ManifestInput (@object-ui/sdui-parser, types.ts) adds the framework-set binding: 'object' marker. It says an input NAMES an object and carries no requiredness.
  • validateTree's only requiredness check is input.required && !(input.name in node).

packages/types is not edited. The same shape already landed in this repo: element:number's object (objectui#10909), and the objectName inputs of object-calendar, object-gantt, object-map and object-timeline, each dropped required and gained a description that names the binding.

Accept-set changes (for the contract review)

Measured against the manifest the console ships (buildArtifacts over dev/manifest-registry.ts). "Before" is this head with required: true put back through ablation-replace.mjs; "after" is this head.

node before after
record:line_items with dataSource.object, relationshipField, columns, no childObject ok: false: one error, missing-required-prop naming childObject ok: true, no diagnostics. The dataSource binding site is recorded in both runs
record:line_items with relationshipField and columns, and neither childObject nor dataSource ok: false: the same error ok: true, no diagnostics. The ruling leaves this node to the runtime: the panel shows the configuration hint naming childObject and fetches nothing. LineItemsPanel.childObjectDecline.test.tsx pins the hint, unchanged and green
record:line_items with childObject, relationshipField and columns ok: true ok: true (control)

Generated artifacts that move with it (same generator, same runs):

  • sdui.manifest.json, entry record:line_items, input childObject: required: true removed, description added.
  • sdui-intrinsics.d.ts (the typed JSX face): childObject: string becomes childObject?: string.
  • sdui-blocks.md, the required-props column for record:line_items: childObject, relationshipField, columns becomes relationshipField, columns.

Unchanged: relationshipField and columns stay required. The zod faces (objectui validate), the spec row and the renderer are not touched.

registry-inputs-spec-parity

apps/console/src/__tests__/registry-inputs-spec-parity.test.ts does not compare requiredness, so nothing in it records this difference and the file is unchanged. Evidence: the file never reads an input's required, and it does read input.of and input.type (the control). It is green on this head.

Pins

New: apps/console/src/__tests__/line-items-bound-child-object-11569.test.ts. It judges against the shipped sdui.manifest.json (written by emitSduiManifest and read back):

  1. The published entry declares childObject as not required, with a description that names dataSource and dataSource.object. relationshipField and columns stay required.
  2. The bound node compiles ok with no diagnostic, and the binding is recorded.
  3. Control: the childObject node compiles ok.
  4. Control: a node that names childObject but has no relationshipField is refused with exactly one missing-required-prop. This row reads the same before and after the fix.
  5. The neither node draws no compile diagnostic about childObject.

Reproduced first: before the fix, rows 1, 2 and 5 were red, each with missing-required-prop naming childObject at error severity.

Ablation, run on the committed fix: ablation-replace.mjs put required: true back (anchor hit once, blob e9b208727dd7 became 2591aef44b45). Rows 1, 2 and 5 turned red (3 failed, 2 passed). The restore is proven by blob hash: e9b208727dd7 equals HEAD and git diff HEAD is empty. On resolution: the console project aliases @object-ui/plugin-form to packages/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.

Other edits

  • LineItemsPanel.tsx and LineItemsPanel.childObjectDecline.test.tsx: comment-only. Two comments said childObject was declared required: true on the registry entry and that the block had no spec schema. They now state the current facts.
  • content/docs/guide/data-source.md: one prose sentence, no code fence. A bound record:line_items node needs no childObject and the page compile accepts it. A node with neither shows the configuration hint.
  • .changeset/11569-line-items-child-object-optional.md: @object-ui/plugin-form minor. A Clause-②: yes widening takes at least minor, which matches the objectui#10909 landing (PR objectui#10944). It was first graded patch and regraded at 84ee3be after the at-tier contract review 5978497549. Its widening paragraph opens with the **Clause-②: yes (widening)** banner.

Verification (head 84ee3be)

84ee3be changes only the changeset (the grade and the banner). The test, build and type-check runs below were taken at 448bac5, whose code is identical. The changeset gates were re-run at 84ee3be: check-changeset-presence, check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims, check:pending-changeset-literals, check:control-bytes and check:new-line-citations each exit 0.

  • pnpm --filter '@object-ui/plugin-form^...' build: exit 0 (12 of 47 projects).
  • pnpm --filter @object-ui/plugin-form type-check: exit 0 (tsc --noEmit && tsc -p tsconfig.test.json).
  • pnpm exec vitest run packages/plugin-form/: exit 0. Test Files 163 passed (163), Tests 1889 passed | 1 skipped (1890).
  • 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 (reads data-source.md) and registered-types-validate-ratchet-10859.
  • 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-roots and check-vi-mock-override-shape: each exit 0.
  • check-governed-queue-guard --test over the six paths: NOT GOVERNED.
  • 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 (no project / projectService), and no custom rule in eslint-rules/ reads the disk, so this diff cannot change the result for an untouched file.
  • NOT MEASURED, left to CI:
    • check:doc-snippets and check:doc-examples stopped at PRECONDITION NOT MET (exit 2) because the packages are unbuilt. The docs edit adds no code fence.
    • The full @object-ui/console type-check needs the whole console closure built. A scoped tsc over 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, in dev/manifest-registry.ts and src/register-plugins.ts.

Acceptance notes

  • LineItemsPanelSchema.childObject (the panel component's TypeScript prop type) is still string, not optional. It is a React prop type, not stored metadata: the gate fills it before the panel reads it, and the panel guards the undefined case. Recorded only. Carrier: none.
  • The same defect class on sibling gate-wrapped blocks is listed in the dev report for the seat to file. Not touched here.

Implemented by the os-dev run under session https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2, for the claim on the card.


Generated by Claude Code

…he page compile accepts a dataSource-bound node (objectui#11569)

The spec row leaves `childObject` optional because the node's `dataSource`
binding can supply it, and `RECORD_LINE_ITEMS_DATA_SOURCE` lands
`dataSource.object` on `childObject` before the panel reads the node. The
registration still declared `required: true`, so the page compile refused a
bound node with `missing-required-prop` at error severity.

The manifest has no "one of these is required" form (`ComponentInput` and
`ManifestInput` carry a boolean `required` only), so the input drops
`required` and gains a description that names the binding. A node with
neither keeps the panel's runtime configuration hint.

New pin: apps/console line-items-bound-child-object-11569, judged against
the shipped sdui.manifest.json.

Claude-Session: https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation plugin apps tests labels Oct 4, 2026
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.4 KB 3330.4 KB
Main entry chunk (gzip) 151.3 KB 350 KB
Entry file index-BwSVgiaT.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 17.22KB 6.37KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.60KB 64.57KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.74KB 45.38KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 448bac5da0780e8787cca5ee514dca17ff57482b
Local-runs: none

Read-only, against: the card (objectui#11569 body, triage 5972410418, claim 5977893924, dev report 5978370413, seat review 5978394943); the PR body, its six-file list and the net diff origin/main 2e818d0..448bac5 (merge-base is 2e818d0, one commit); the published @objectstack/spec 17.6.0 tarball (npm pack, dist/ui/index.mjs); objectui main 2e818d0 and the head by git show. Check-runs on the head at the final read (2026-10-04T09:23:01Z): 43 runs, 40 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot), 0 failed, 0 in progress; the head is still 448bac5. The one PR comment is the performance-budget and bundle-size bot; no bot re-read a pending changeset, so no paragraph is judged false there. The seat's review was read as a claim to test, and every reading below is my own.

① Derived judgments

  1. The page compile accepts a dataSource-bound record:line_items node with no childObject: right. The diff removes required: true from that one input and adds a description; nothing else moves in packages/plugin-form/src/index.tsx. The spec row (17.6.0 RecordLineItemsProps) reads childObject: z.string().optional(), described "Optional because the component-level dataSource binding can supply the object instead". The runtime agrees: ElementDataSourceGate (packages/react/src/element-data-source/ElementDataSourceGate.tsx) writes next[objectKey] = composed.object whenever a binding is present, and RECORD_LINE_ITEMS_DATA_SOURCE maps object to childObject. The page compile was the only face refusing what the row, the zod faces and the renderer accept. Pinned by rows 2 and 3 of the new test, red first and ablated.

  2. The neither-node now compiles too: consistent with the row and the ruling, not a hidden authoring error. The row's own describe continues "with neither, the panel shows a configuration hint and fetches nothing": the published contract already accepts the neither-node and names the runtime hint as its answer. Triage says the same ("The runtime's visible config hint for a node with neither stays the answer there") and forbids new manifest vocabulary in this card. The refusal the gate used to raise was one the contract never asked for; objectui validate accepted the neither-node before and after. The hint is visible and pinned (LineItemsPanel.childObjectDecline.test.tsx, unchanged and green; form.lineItems.noChildObject renders the property name as code). The trade-off is stated in the changeset body ("A node that names its child object in neither place also compiles now"). Whether a one-of form is wanted is a question for its own card; see ③ item 6.

  3. The "no one-of-required vocabulary" finding is true. ComponentInput (packages/types/src/base.ts) carries required?: boolean; its zod twin ComponentInputSchema (packages/types/src/zod/base.zod.ts) carries required: z.boolean().optional(). ManifestInput (packages/sdui-parser/src/types.ts) carries required?: boolean and binding?: 'object', the latter documented as "the input NAMES an object", not requiredness. validateTree's only requiredness read is if (input.required && !(input.name in node)) (validate.ts), and its only binding read records a site, waiving nothing. No either-or form exists on either type or in the compiler.

  4. No document that compiled before is refused now. The diff removes one check and adds a description. validateTree reads description nowhere (its one occurrence is the base-prop table); the serializer forwards it as a passive field (sdui-parser/src/index.ts). Monotone widening. relationshipField and columns stay required: true, and row 4 of the pin is the before-and-after control on that.

  5. Emitted typings and block list: right, and nothing regenerated is owed. sdui.manifest.json, sdui-intrinsics.d.ts and sdui-blocks.md are written by buildArtifacts (packages/sdui-parser/scripts/gen-manifest.ts) at build time; none is tracked at main 2e818d0 (git ls-tree). childObject?: string and the required column relationshipField, columns follow from the same manifest entry; row 1 of the pin reads that entry from the shipped manifest.

  6. The published description is accurate. "dataSource.object lands on this key, outranking an authored value": the gate's precedence table reads "dataSource.* keys are authoritative" and the compose is unconditional. "With neither, the panel shows a configuration hint naming this key and loads nothing": the panel declines both fetches on a falsy childObject and renders the hint with the property as code. The description opens with the row's own describe, as the calendar, gantt, map and timeline objectName inputs do.

  7. What publishes. @object-ui/plugin-form's record:line_items registration (the ComponentRegistry entry's inputs) loses required: true on childObject and gains a description; the host-emitted manifest entry, typings and block list move from it. No export of @object-ui/plugin-form, @object-ui/types or @object-ui/sdui-parser is added, removed or renamed; packages/types is untouched, honouring objectui#8347's hold.

② Semver level

  • Clause-②: yes is right. The page compile is a public door and its accept set widens: a bound node, and the neither-node, go from ok: false to ok: true (the PR's own table). A published registration's declared input changes shape. That is the declaration's criterion, and the honest direction.
  • patch does not match it. The changeset must grade @object-ui/plugin-form minor. The fleet rule is explicit: a bug fix in a released package takes patch UNLESS the PR declares Clause-②: yes, in which case at least minor (objectstack AGENTS.md, Post-Task Checklist item 3, recording the maintainer ruling "a purely additive widening of a published package's public surface takes at least minor"); the fleet's scripts/check-changeset-no-major.mjs LEVEL axis mechanises it and names the pair in this PR by shape: "A declaration of ① plus a patch in ② is a self-contradiction inside one PR". objectui's own practice agrees where the declaration is yes: .changeset/11564-flex-bag-children-list.md on main reads "shipped as minor per this repository's version policy", and the closest precedent, element:number's object no longer required because the binding supplies it (dd0d78f, PR objectui#10944, 2026-09-28, objectui#10909), declared Clause-②: yes (widening) and graded @object-ui/components minor, under Minor Changes in its CHANGELOG with the banner. The PR body cites that landing as the shape it repeats, then grades below it.
  • The precedent picture, read in full so the seat can weigh it: the two older landings of this shape, PR objectui#10390 (3ef0b51, 2026-09-24, map and gantt) and PR objectui#10508 (875ee61, 2026-09-25, calendar), declared Clause-②: no and shipped patch, each a consistent pair; objectui#10944 declared yes (widening) and shipped minor, also consistent. This PR pairs yes with patch, which is neither. Flipping the declaration to no to keep patch is not open: the accept set measurably widens and the claim has declared it. objectui's Changeset Bump Policy check judges major only (its check-changeset-no-major.mjs has no LEVEL axis), so its green carries no information on this axis.
  • The claim 5977893924 prescribed "one @object-ui/plugin-form patch changeset" beside Clause-②: yes, so the contradiction originates in the dispatch; the dev executed the claim as written. The repair is one line in .changeset/11569-line-items-child-object-optional.md, patch to minor; the body already describes the widening. Recommended, not required: open the body's second paragraph with the **Clause-②: yes (widening)** banner the repository's recent minors carry.

③ Boundary flags

  1. Pin in apps/console, not plugin-form: accepted. It reads the manifest the console ships (emitSduiManifest over dev/manifest-registry.ts), the save gate's own input, through the same import pair sdui-manifest-build-11403.test.ts already uses in that directory; a plugin-form placement would add @object-ui/sdui-parser as a devDependency for one test. @object-ui/console is versioned, but the change there is a test file, so no second changeset is owed; Changeset Declaration is green.
  2. Comment-only rewrites and the data-source.md sentence: accepted, each sentence checked. The two old comments said childObject was required: true on the registry entry (false after this diff) and that the block "has no spec schema at all" (false since 17.6.0's RecordLineItemsProps); the replacements state that the row and the entry both leave it optional and name the binding, which is what this review measured. The docs sentence's three clauses (a bound node needs no childObject; the page compile accepts it; the neither-node shows a hint naming childObject and loads nothing) each match the gate compose, the compile result and form.lineItems.noChildObject. Prose faces are outside the contract tier; judged here because the brief asked.
  3. Hypothesis 4 falsified: confirmed. registry-inputs-spec-parity.test.ts at 2e818d0 has no read of an input's required (29 textual hits, all requiredPermissions members or prose); it reads input.type and input.of. Unchanged is right.
  4. Family finding: right to fold, right that it is outside this card. At 2e818d0, object-grid (plugin-grid/src/index.tsx), object-kanban (plugin-kanban/src/index.tsx) and the plugin-dashboard registrations still declare { name: 'objectName', type: 'string', required: true } while their 17.6.0 rows make objectName optional for the binding. Triage scoped this card to one registration and forbade new vocabulary. The seat filed objectui#11605 (open, unlabelled, awaiting triage) as the family's closing card; nothing from it is owed here.
  5. LineItemsPanelSchema.childObject stays string: the acceptance note is the right carrier, with one correction to its framing. The type IS a published export (packages/plugin-form/src/index.tsx line 67 re-exports it), not only an internal prop type. Leaving it is still right: it types the panel's input AFTER the gate composes the binding, where childObject is present on every bound node; the two fetch guards handle the undefined case; and loosening a published type is a second Clause-② surface outside this card. No defect, no card.
  6. Escalated to the seat, not blocking. Whether a "one of these is required" manifest form is wanted at all is the question triage left open ("If one is wanted, it is its own card"). Nothing in this diff presumes an answer; with objectui#11605 lining up six more registrations that will drop required the same way, the seat may want the question in the decision box before the family closes rather than after.

Implemented-by: claude/issue-11569-line-items-childobject
Reviewed-by: session_01FjqrwXPfSMkSfkKYDSRkN2

VERDICT: FAIL

Written 2026-10-04T09:24Z. FAIL on ② alone, the changeset level. ① and ③ hold. A patch round that regrades @object-ui/plugin-form to minor on this diff, with the check-runs green on the new head, is the whole of what a PASS needs.

…r, with the Clause-② widening banner

The PR declares `Clause-②: yes`: the page compile's accept set widens for a
`record:line_items` node bound through `dataSource` (and for one with
neither). A `yes` declaration takes at least `minor`, as objectui#10909's
`element:number` landing shipped. The widening paragraph now opens with the
`**Clause-②: yes (widening)**` banner. Nothing else moves.

Claude-Session: https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.4 KB 3330.4 KB
Main entry chunk (gzip) 151.3 KB 350 KB
Entry file index-BwSVgiaT.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 17.22KB 6.37KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.60KB 64.57KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.74KB 45.38KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 84ee3bec8d09b44bab9c3814694f7baebd51a36c
Local-runs: none

Re-review after the FAIL record 5978497549 on 448bac5. Read-only, against: the card (objectui#11569 body, triage 5972410418, claim 5977893924, dev reports 5978370413 and 5978525063, seat review 5978394943, seat answer 5978504784); the PR body as it reads now, its six-file list and the net diff origin/main..84ee3be (merge-base 2e818d0; two commits, 448bac5 then 84ee3be); the published @objectstack/spec 17.6.0 tarball; objectui main 278d244 and the head by git show. Check-runs on the head at the final read (2026-10-04T09:46:18Z): 43 runs, 40 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot), 0 failed, 0 in progress; the head is still 84ee3be. The PR's two bot comments are both performance-budget and bundle-size reports; neither re-reads a pending changeset, so no paragraph is judged false there.

What 84ee3be changes, read from the head: one file, .changeset/11569-line-items-child-object-optional.md, two lines. The grade '@object-ui/plugin-form': patch becomes minor, and the widening paragraph's opener **Behaviour change.** becomes **Clause-②: yes (widening)** —. The other five files are blob-identical to 448bac5 (index.tsx e9b208727dd7, LineItemsPanel.tsx 37d28b38d682, LineItemsPanel.childObjectDecline.test.tsx 24e1a548c157, line-items-bound-child-object-11569.test.ts 2705b2d774f7, data-source.md 06befbfa97a3), so every code reading below was re-taken on this head and holds unchanged. main advanced by two commits since the first record (b61c116, 278d244); neither touches a PR file or any surface this review relies on (packages/plugin-form/src, packages/sdui-parser, packages/types/src/base.ts, zod/base.zod.ts, apps/console/dev/manifest-registry.ts, emit-sdui-manifest.ts, packages/react/src/element-data-source, the parity test), and the lockfile on 278d244 still resolves @objectstack/spec@17.6.0.

① Derived judgments

  1. The page compile accepts a dataSource-bound record:line_items node with no childObject: right. On this head the registration (packages/plugin-form/src/index.tsx, the inputs list) declares childObject with type: 'string' and a description, no required; relationshipField and columns keep required: true. The spec row (17.6.0 RecordLineItemsProps) is childObject: z.string().optional(), "Optional because the component-level dataSource binding can supply the object instead". ElementDataSourceGate writes next[objectKey] = composed.object whenever a binding is present, and RECORD_LINE_ITEMS_DATA_SOURCE maps object to childObject. The page compile was the one face refusing what the row, the zod faces and the renderer accept. Pinned by rows 2 and 3 of the new test, red first and ablated (round 0, code identical).

  2. The neither-node now compiles too: consistent with the row and the ruling. The row's describe continues "with neither, the panel shows a configuration hint and fetches nothing", so the contract already accepts the neither-node and names the hint as its answer; triage says the same and forbids new vocabulary in this card. objectui validate accepted the neither-node before and after. The hint is visible and pinned (LineItemsPanel.childObjectDecline.test.tsx; form.lineItems.noChildObject renders the property as code). The changeset body states the trade-off ("A node that names its child object in neither place also compiles now").

  3. The "no one-of-required vocabulary" finding is true. ComponentInput carries required?: boolean; ComponentInputSchema carries required: z.boolean().optional(); ManifestInput carries required?: boolean and binding?: 'object' ("the input NAMES an object"); validateTree's only requiredness read is if (input.required && !(input.name in node)), and its binding read records a site, waiving nothing.

  4. No document that compiled before is refused now. One check removed, one passive description added; validateTree reads description nowhere and the serializer forwards it. Monotone widening; row 4 of the pin is the before-and-after control on relationshipField.

  5. Emitted typings and block list: right, nothing regenerated is owed. sdui.manifest.json, sdui-intrinsics.d.ts and sdui-blocks.md are build-time outputs of buildArtifacts; none is tracked on main 278d244. childObject?: string and the required column relationshipField, columns follow from the same entry; row 1 of the pin reads it from the shipped manifest.

  6. The published description is accurate. "dataSource.object lands on this key, outranking an authored value" matches the gate's "dataSource.* keys are authoritative" and its unconditional compose; "With neither, the panel shows a configuration hint naming this key and loads nothing" matches the two fetch guards and the hint.

  7. What publishes. @object-ui/plugin-form's record:line_items registration loses required: true on childObject and gains a description; the host-emitted manifest, typings and block list move from it. No export is added, removed or renamed in @object-ui/plugin-form, @object-ui/types or @object-ui/sdui-parser; packages/types is untouched.

② Semver level

  • Clause-②: yes is right, for the reason the first record gave: the page compile's accept set widens (bound node and neither-node, ok: false to ok: true) and a published registration's declared input changes shape. The line stands at line 2 of the PR body, at line start.
  • minor now matches it. The changeset on this head grades '@object-ui/plugin-form': minor, the level a Clause-②: yes declaration takes at least (objectstack AGENTS.md, Post-Task Checklist item 3; the fleet LEVEL axis), and the level objectui's closest precedent shipped (element:number, objectui#10909, PR objectui#10944, minor with the banner). The yes-plus-patch self-contradiction the first record failed on is gone. Frontmatter is well-formed; the fixed-group and no-major rules are met (Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Claim Re-read and Changeset Overwrite Report all success on this head).
  • The banner is in the repository's form. The widening paragraph opens **Clause-②: yes (widening)** —, the em-dash spelling of the element:number minor on main (packages/components/CHANGELOG.md). Replacing the **Behaviour change.** label rather than stacking two bold openers is the right call; the paragraph's content is otherwise unchanged and still names both accept-set moves and the two inputs that stay required.
  • The PR body's changeset bullet and its Verification section were updated to this head (the bullet names the regrade, the review that asked for it and the banner; the Verification section says 84ee3be changes only the changeset and lists the eight changeset gates re-run there). Each sentence checked against the diff and the dev report; all true.

③ Boundary flags

  1. Pin in apps/console, not plugin-form: accepted. It reads the manifest the console ships through the import pair sdui-manifest-build-11403.test.ts already uses; a plugin-form placement would add @object-ui/sdui-parser as a devDependency for one test. The console change is a test file, so no second changeset is owed.
  2. Comment-only rewrites and the data-source.md sentence: accepted. Both old comments stated facts this diff and 17.6.0 made false; the replacements state what this review measured. The docs sentence's three clauses each match the gate compose, the compile result and form.lineItems.noChildObject. Prose faces are outside the contract tier; judged because the brief asked.
  3. Hypothesis 4 falsified: confirmed. registry-inputs-spec-parity.test.ts (unchanged on main 278d244) has no read of an input's required; it reads input.type and input.of.
  4. Family finding: right to fold, outside this card. object-grid, object-kanban and the plugin-dashboard registrations still declare objectName required: true against rows that make it optional; objectui#11605 is the family's closing card; nothing from it is owed here.
  5. LineItemsPanelSchema.childObject stays string: acceptance note is the right carrier. The type is a published export (index.tsx line 67) typing the panel's input after the gate composes the binding; the fetch guards cover undefined; loosening it is a second Clause-② surface outside this card. No defect, no card.
  6. The one-of-required vocabulary question: recorded, not decided, nothing owed here. The seat answer 5978504784 carries it to objectui#11605 for triage before that family is dispatched. This diff presumes no answer.
  7. Round-1 deviations: accepted. The banner replacing the old label is covered in ②. The worktree was re-added on the same branch after checking the remote head equalled 448bac5, with no lockfile change. The new commit carries the model-free trailer pair the repository asks for, and the PR body keeps one session-URL footer.

Implemented-by: claude/issue-11569-line-items-childobject
Reviewed-by: session_01FjqrwXPfSMkSfkKYDSRkN2

VERDICT: PASS

Written 2026-10-04T09:51Z. The FAIL on ② is cleared on this head by the changeset alone; ① and ③ hold as on 448bac5, whose code this head carries byte for byte. Every check-run on 84ee3be is complete and none failed.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

needs:contract-review removed: an at-tier PASS is on record at this head · domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-04T09:52Z.

  • Record: 5978691275 on this PR: ## Contract review, Served-tier: CONTRACT_REVIEW_TIER, Head-sha: 84ee3bec8d09b44bab9c3814694f7baebd51a36c, Local-runs: none, Implemented-by: claude/issue-11569-line-items-childobject / Reviewed-by: session_01FjqrwXPfSMkSfkKYDSRkN2, PASS.
  • Its history:
    • The same reviewer's FAIL 5978497549 on 448bac5 stands for that head. Its item ② was this seat's error: the claim paired Clause-②: yes with a patch changeset, where yes takes at least minor. The seat owned the error in 5978504784 on objectui#11569.
    • The dev's commit 84ee3be changed only the changeset. The grade went patch → minor, and the widening paragraph now opens **Clause-②: yes (widening)** —. The seat read the compare 448bac5...84ee3be: one file, +2 / −2. The PASS re-renders on that head, and ① and ③ hold byte for byte.
  • The reviewer's writes: none. It ran read-only, and the seat posted both records from its record files. Nothing was edited: no label, no review, no ready flip.
  • Pre-landing checks on 84ee3be:
    • 43 check runs: 40 success and 3 expected skips (dependabot, Test (coverage) and its shard matrix);
    • mergeable_state: clean;
    • check-governed-merges --pr objectstack-ai/objectui#11604: NOT governed, 191 changed lines, under the human-merge threshold.
  • The PR body is the dev's pr_body_update, written by the seat. The record judged every sentence true against this head.
  • Carried, not owed here: the one-of-required manifest vocabulary question (record ③.6) is on objectui#11605 for triage, the family's closing card. LineItemsPanelSchema.childObject stays string, an Acceptance note (③.5).
  • Landing in this act: ready, then auto-merge, so the PR enters the merge queue. Fixes #11569 closes the card on merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 4, 2026 09:53
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 4, 2026 09:53
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 4, 2026
Merged via the queue into main with commit 902ebab Oct 4, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11569-line-items-childobject branch October 4, 2026 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apps documentation Improvements or additions to documentation plugin tests

Projects

None yet

2 participants