… only; the column `options` read is retired (objectui#11544)
`groupValueFormatter` read `columns[].options` ahead of the object field's
`options`. `ListColumnSchema` is strict and declares no `options`, so the
read honoured a key every publish refuses. The labels now come from the
object field's `options` only; the column lookup stays for the declared
`type` member and is typed as `ListColumn`, so an undeclared member read no
longer compiles there.
The 8071 grouping fixture's label cases are turned to pin the field's
labels (with a column `options` beside them that must not appear, and a
no-field-options control); the `order` case sorts by the field's labels.
The console parity ledger's `object-grid.grouping` descriptor follows.
Claude-Session: https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2
Co-authored-by: Claude <noreply@anthropic.com>
Fixes #11544
Clause-②: no
Retire, not widen (triage ruling
5966937083): a groupedobject-gridlabels its group headers from the object field'soptionsonly.ListColumnSchemadeclares nooptionsand is strict, so the column-level read honoured a key every publish refuses. Sessionsession_01FjqrwXPfSMkSfkKYDSRkN2, branchclaude/issue-11544-group-header-field-options.What changed
packages/plugin-grid/src/ObjectGrid.tsx,groupValueFormatter: the label sourcecolOverride?.options || objectDefField?.optionsis nowobjectDefField?.options. The column lookup stays, because it also suppliestype, a declaredListColumnmember (abooleancolumn respells"true"/"false"as Yes / No). The lookup is now typed asListColumn, with the samec is ListColumnguardmaskedGroupingSignaturealready uses, instead ofas any[]. As a result, an undeclared column-member read at this site no longer compiles (proved below).packages/plugin-grid/src/__tests__/gridGroupingMembers-8071.test.tsx: the two cases that pinnedcolumns[].optionsas behaviour are turned to pin the field's labels:optionsdecide the header label, and a columnoptionsbeside them is not read". It has three legs. The field's labels reach the header. A column carryingoptionsbeside the field's still shows the FIELD's labels. The same column with no field options shows the stored values.ordersorts the RENDERED labels, so the field's options move the groups". This isorder: 'asc'over the field's labels, with a no-field-labels control.renderGroupednow takes the hostobjectFieldsruntime prop, which is how field options reach an inline-rows grid without a schema read.apps/console/src/__tests__/registry-inputs-spec-parity.test.ts: theobject-grid.groupingpinsdescriptor follows the fixture; it had said the read was pinned as behaviour and not repaired. This is the move PR feat(types,plugin-grid)!: object-grid and list-view conditionalFormatting take the spec list view's { condition, style } rule only; the native dialect is refused by name (objectui#11533) #11540 made to its own descriptor. It is text only: nothing asserts onpinscontent..changeset/11544-group-header-field-options.md:@object-ui/plugin-gridpatch.Premise, measured on
origin/maind0c0c7fe9(after PR #11554)@objectstack/spec17.6.0ListColumnSchemahas fourteen keys (field, label, width, align, hidden, sortable, resizable, wrap, type, pinned, summary, prefix, link, action).safeParse({ field, options })answersunrecognized_keysnamingoptions, and the control{ field, type: 'select' }parses.ObjectGridSchema.safeParsewith a columnoptionsanswersinvalid_unionatcolumns, and the same grid with a columntypeparses..optionsinObjectGrid.tsxfinds only thegroupValueFormatterline reading it off a column; every other hit reads a field. A repo grep for the column-override lookup finds only this memo. Othercol.optionshits (GridField,RecordPickerDialog, the flow inspector) read different column schemas, notListColumn, and none of them labels a group.options: none. Theoptionsspreads in app-shell build detail-form fields and import targets, not grid columns.typeneeds the lookup, so it stays, typed.Tests (HEAD
92bddae)pnpm exec vitest run --maxWorkers=2 packages/plugin-grid/src/__tests__/gridGroupingMembers-8071.test.tsx apps/console/src/__tests__/registry-inputs-spec-parity.test.tsgivesTest Files 2 passed (2)andTests 265 passed (265).pnpm exec vitest run --maxWorkers=2 packages/plugin-grid/givesTest Files 182 passed (182)andTests 1691 passed (1691).pnpm --filter @object-ui/plugin-grid type-check(tsc --noEmit && tsc -p tsconfig.test.json) exits 0.--listFilesontsconfig.test.jsonlists the fixture once andObjectGrid.tsxonce.pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-grid^...' buildexits 0.Ablation (one-shot, run from the committed fix through objectstack's
scripts/ablation-replace.mjsin wrap mode)const rawOptions = objectDefField?.options;, replaced withconst rawOptions = (colOverride as any)?.options || objectDefField?.options;(anchor count 1 to 0, blob004444984f55to316153fc4622). Predicted: the label case goes red and everything else stays green. Observed:Tests 1 failed | 9 passed (10),expected [ 'Column Lost', 'Column Won' ] to deeply equal [ 'Closed Lost', 'Closed Won' ]. Restore: blob equals HEAD, andgit diff HEADis empty.const rawOptions = colOverride?.options || objectDefField?.options;.tsc --noEmitgiveserror TS2339: Property 'options' does not exist on type(theListColumnobject shape). Restore: blob equals HEAD.ordercase stays green under the behaviour ablation by design. It carries no columnoptions; it pins thatordersorts the field's labels, which both trees do.Gates (HEAD
92bddae, each exit 0)pnpm check:control-bytes:check-control-bytes: OK.pnpm check:new-line-citations:VERDICT new-cross-file-line-citations: 0 new citation(s).node scripts/check-changeset-presence.mjs:3 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s).node scripts/check-changeset-no-major.mjs,check-changeset-fixed.mjsandcheck-changeset-overwrite.mjs: all report OK.pnpm check:changeset-claimsis report-only. It names six pending changesets that mentionObjectGrid.tsxor the parity ledger. I re-read each paragraph, and none makes a claim about group-header labels or columnoptions.pnpm check:pending-changeset-literals:No test source names a pending changeset.pnpm check:test-path-roots,node scripts/check-vi-mock-specifiers.mjs,node scripts/check-vi-mock-inherit.mjs,pnpm check:spec-symbolsandnode scripts/check-type-check-coverage.mjs: all report OK.Narrowings (declared)
eslint --print-configresolves all three, so none is ignored.--format jsoncounts 3 files.eslint.config.jssets noparserOptions.project/projectService, so type-aware linting is off, and this diff cannot move an untouched file's verdict. In package form (inline config honoured, aspnpm lintruns it): 0 errors. In root--no-inline-configform: 1 error,react-hooks/static-components, at the annotatedAuthoredEmptyIconsite. It is identical at BASE (BASE 1 error / 210 warnings, head 1 / 209).check:published-dist,check:node-esm-load,check:phantom-depsand the rest) and the full shardedpnpm testbelong to CI. This diff adds no import, export or dependency.Acceptance notes
columns[].options, is left as written. It records what that slice did, the way a changelog entry does. Only the livepinsdescriptor changed.content/docsandpackages/plugin-grid/README.md), so there is no doc edit.object-grid.groupingentry.columnsby reference once its.objectui-shacovers this landing. That stays on objectstack#21464, per triage.Generated by Claude Code