Provenance: measured while implementing objectui#6711 (retiring the dead
reference_to_field from the same list). Filed unassigned. Not folded into that card — it
names one key and removes it; this is the opposite direction (keys with readers that are
never copied) and is a behaviour change, not a retirement.
What's measured
ObjectGrid's applyRelationalMeta copies a fixed list off the object-schema field def onto
each relational column's fieldMeta (packages/plugin-grid/src/ObjectGrid.tsx,
RELATIONAL_META_KEYS), and that bag is what the cell renderer and the inline picker
receive. The list is a strict SUBSET of what those two consumers read off the same bag.
Consumer reads, verbatim from packages/fields:
src/index.tsx (LookupCellRenderer):
display_field || displayField || reference_fieldsrc/widgets/LookupField.tsx:252 (the grid's inline picker):
fieldMeta?.display_field || fieldMeta?.displayField || fieldMeta?.reference_field || 'name'src/widgets/LookupField.tsx:253:
fieldMeta?.description_field ?? fieldMeta?.descriptionFieldsrc/widgets/LookupField.tsx:268:
fieldMeta?.lookup_columns ?? fieldMeta?.lookupColumnssrc/widgets/UserField.tsx:49:
meta?.display_field || meta?.displayField || meta?.reference_field
Copied by the grid: display_field, description_field, lookup_filters, lookupFilters,
id_field, reference_to, reference (+ titleFormat, see objectui#6874).
Never copied, though read on the grid's own path:displayField, reference_field,
descriptionField, lookup_columns, lookupColumns.
Why this is not "the renderer just accepts extra spellings"
Two things make the omission specific rather than cosmetic:
reference_field is a DECLARED objectui type member with readers all over the repo —
packages/types/src/field-types.ts (LookupFieldMetadata.reference_field),
packages/types/src/views.ts, its zod mirror, and read by plugin-detail
(RelatedList, RecordMetaFooter, RecordDetailDrawer, fieldEnrichment),
plugin-charts (ObjectChart), plugin-form (deriveMasterDetail), plugin-list
(ListView, UserFilters) and app-shell (resolveActionParams). Every one of those
surfaces honours an author's reference_field; a lookup rendered by ObjectGrid does
not, because the key never reaches the cell.
The camelCase spellings are the SPEC-declared ones.@objectstack/spec@17.2.0's
FieldSchema (64 props) declares displayField, descriptionField, lookupColumns,
lookupFilters, reference — and none of display_field, description_field,
lookup_filters, reference_to. The grid's list is mostly the objectql runtime
spellings. It is internally inconsistent about this: lookupFilters (camel) IS in the
copy set next to lookup_filters, while displayField and descriptionField are not
next to their snake twins — so the list was assembled from a defect report rather than
derived from the readers.
What is NOT measured here
- Whether the object schema a live
getObjectSchema returns ever carries the camelCase
spellings (the server may normalise on the way out). That check decides how much of item 2
is reachable today, and it is the first thing triage should run. - No user report is attached. This is a static producer-vs-consumer measurement.
packages/plugin-dashboard's CELL_RELATIONAL_META_KEYS has the same gap for
displayField / reference_field: its docblock enumerates what LookupCellRenderer
reads as three keys, and that enumeration missed the two extra spellings in the same
fallback chain.
Shape of a fix
Contract-first says the answer may be at the producer (one spelling, normalised once) rather
than widening a hand-kept alias list in the renderer — AGENTS.md #0.1 is explicit that a
tolerant renderer fossilises a second dialect. Whatever the direction, the copy set should
be DERIVED from the consumers' read set rather than restated, so the two cannot drift again;
that is the same repair objectui#6711 and objectui#6874 approach from the dead-key side.
Generated by Claude Code
Generated by Claude Code
Provenance: measured while implementing objectui#6711 (retiring the dead
reference_to_fieldfrom the same list). Filed unassigned. Not folded into that card — itnames one key and removes it; this is the opposite direction (keys with readers that are
never copied) and is a behaviour change, not a retirement.
What's measured
ObjectGrid'sapplyRelationalMetacopies a fixed list off the object-schema field def ontoeach relational column's
fieldMeta(packages/plugin-grid/src/ObjectGrid.tsx,RELATIONAL_META_KEYS), and that bag is what the cell renderer and the inline pickerreceive. The list is a strict SUBSET of what those two consumers read off the same bag.
Consumer reads, verbatim from
packages/fields:src/index.tsx(LookupCellRenderer):display_field || displayField || reference_fieldsrc/widgets/LookupField.tsx:252(the grid's inline picker):fieldMeta?.display_field || fieldMeta?.displayField || fieldMeta?.reference_field || 'name'src/widgets/LookupField.tsx:253:fieldMeta?.description_field ?? fieldMeta?.descriptionFieldsrc/widgets/LookupField.tsx:268:fieldMeta?.lookup_columns ?? fieldMeta?.lookupColumnssrc/widgets/UserField.tsx:49:meta?.display_field || meta?.displayField || meta?.reference_fieldCopied by the grid:
display_field,description_field,lookup_filters,lookupFilters,id_field,reference_to,reference(+titleFormat, see objectui#6874).Never copied, though read on the grid's own path:
displayField,reference_field,descriptionField,lookup_columns,lookupColumns.Why this is not "the renderer just accepts extra spellings"
Two things make the omission specific rather than cosmetic:
reference_fieldis a DECLARED objectui type member with readers all over the repo —packages/types/src/field-types.ts(LookupFieldMetadata.reference_field),packages/types/src/views.ts, its zod mirror, and read byplugin-detail(
RelatedList,RecordMetaFooter,RecordDetailDrawer,fieldEnrichment),plugin-charts(ObjectChart),plugin-form(deriveMasterDetail),plugin-list(
ListView,UserFilters) andapp-shell(resolveActionParams). Every one of thosesurfaces honours an author's
reference_field; a lookup rendered byObjectGriddoesnot, because the key never reaches the cell.
The camelCase spellings are the SPEC-declared ones.
@objectstack/spec@17.2.0'sFieldSchema(64 props) declaresdisplayField,descriptionField,lookupColumns,lookupFilters,reference— and none ofdisplay_field,description_field,lookup_filters,reference_to. The grid's list is mostly the objectql runtimespellings. It is internally inconsistent about this:
lookupFilters(camel) IS in thecopy set next to
lookup_filters, whiledisplayFieldanddescriptionFieldare notnext to their snake twins — so the list was assembled from a defect report rather than
derived from the readers.
What is NOT measured here
getObjectSchemareturns ever carries the camelCasespellings (the server may normalise on the way out). That check decides how much of item 2
is reachable today, and it is the first thing triage should run.
packages/plugin-dashboard'sCELL_RELATIONAL_META_KEYShas the same gap fordisplayField/reference_field: its docblock enumerates whatLookupCellRendererreads as three keys, and that enumeration missed the two extra spellings in the same
fallback chain.
Shape of a fix
Contract-first says the answer may be at the producer (one spelling, normalised once) rather
than widening a hand-kept alias list in the renderer —
AGENTS.md#0.1 is explicit that atolerant renderer fossilises a second dialect. Whatever the direction, the copy set should
be DERIVED from the consumers' read set rather than restated, so the two cannot drift again;
that is the same repair objectui#6711 and objectui#6874 approach from the dead-key side.
Generated by Claude Code
Generated by Claude Code