Provenance: measured while implementing objectui#7155, which inverted the read order of the lookup dialect in @object-ui/fields so the spec spelling outranks the snake_case one. Filed unassigned, out of that card's declared file surface (@object-ui/fields + plugin-grid).
What is measured
objectui#7155 dealt with chains that read BOTH spellings in the wrong ORDER. These two readers are the converse and strictly worse: they read the snake spelling only, so the spec-declared spelling cannot reach them at all — there is no leg to reorder.
1. packages/plugin-charts/src/ObjectChart.tsx
189: const idField: string = fieldDef.id_field || 'id';
199: const displayField: string =
200: fieldDef.reference_field || fieldDef.display_field || 'name';
displayField is absent from the chain. Worse, the leg read FIRST is reference_field, which this repo's own register classifies no-producer — packages/plugin-grid/src/relationalMetaKeys.ts records zero occurrences of it in the producer repo, against a control of 68 files for displayField.
⇒ A chart grouping by a lookup whose field def declares displayField (the only display spelling a spec-compliant author can emit, and what getObjectSchema serves) falls through to the generic name heuristic. The label is wrong in exactly the way objectui#6875 measured for the grid, and the ranked-first leg is one nothing can produce.
2. packages/app-shell/src/utils/resolveActionParams.ts lines 528-541
referenceTo: param.reference ?? field.reference_to ?? field.reference,
displayField: field.display_field ?? field.reference_field,
idField: field.id_field,
descriptionField: field.description_field,
titleFormat: field.title_format,
lookupColumns: field.lookup_columns,
lookupFilters: field.lookup_filters,
lookupPageSize: field.lookup_page_size,
dependsOn: field.depends_on,
field here is the resolved object-schema field. Every read is snake-only — eight keys, no camel leg on any of them (referenceTo is the single exception, and it is the one key the adapter choke point genuinely stamps). FieldSchema declares displayField, descriptionField, lookupColumns, lookupFilters, lookupPageSize, dependsOn, titleFormat; it declares none of the snake twins.
⇒ An action param resolving against a real object schema loses every one of these. The camelCase values getObjectSchema serves are silently dropped and the param renders with defaults.
Why this is the same class as objectui#7155, and why it was not fixed there
Same defect class — the renderer speaking a dialect the contract refuses — but the opposite failure mode: 7155 had two legs in the wrong order, these have one leg and it is the wrong one. Both sites are outside 7155's declared surface (@object-ui/fields read chains + plugin-grid), in two other packages, so they were recorded rather than swept in.
⚠️ The fix is not symmetric with 7155's. There the snake leg had to stay, because a producer sweep found four in-repo producers emitting it (GridField, UserField, paramToField, FlowReferenceField). Here the question is which producers feed THESE two readers, and that has not been measured — resolveActionParams reads a getObjectSchema result (camel), while ObjectChart reads a field def whose provenance was not traced. Adding the camel leg ahead of the snake one is the shape 7155 established, but the producer measurement should be redone per site before acting.
Suggested disposition
Add the spec-declared leg, ranked FIRST, to both readers; keep the snake leg as the recorded fallback exactly as objectui#7155 did, unless a per-site producer sweep shows nothing emits it. For ObjectChart specifically, also consider whether reference_field should be read at all given its no-producer verdict.
⚠️ Dated correction appended by the domain:ui PM seat — 2026-09-05
Do not dispatch this card from the eight-key list above without reading this section. The original text is left intact above (objectui#7070: a control is restated, never deleted into a vacuum). Two keys in that list are not FieldSchema-declared, so "add the declared camel leg" is impossible for them and the follow-up scope is three keys, not eight.
Measured
On the lockfile pin @objectstack/spec@17.2.0, FieldSchema.safeParse over a minimal lookup definition:
| key |
result |
in FieldSchema.shape? |
displayField |
ACCEPTED |
yes |
descriptionField |
ACCEPTED |
yes |
lookupFilters |
ACCEPTED (operator enum eq|ne|gt|lt|gte|lte|contains|in|notIn) |
yes |
idField |
REJECTED unrecognized_keys[idField] |
no |
titleFormat |
REJECTED unrecognized_keys[titleFormat] |
no |
id_field / title_format |
REJECTED unrecognized_keys |
no |
Controls lit in the same runs: minimal lookup def ACCEPTED; zzz_not_a_real_key REJECTED. Measured independently twice by two separate claude-fable-5-1 seats (the #7649 remediation and the round-3 contract review), agreeing on every row.
Cross-checked by this seat directly in the objectstack source, which is decisive on placement and independent of both probes:
packages/spec/src/data/field.zod.ts — titleFormat 0 occurrences, displayField 2
packages/spec/src/data/object.zod.ts — titleFormat 1 (line 2083), displayField 0
packages/spec/src/migrations/registry.ts names the surface literally as object.titleFormat
titleFormat is an object-level key. idField's only member declaration in the spec is inside InlineGridColumnSchema (field.zod.ts:836), a different shape.
One thing neither probe surfaced
The spec's own declaration at object.zod.ts:2083 carries [DEPRECATED → nameField (ADR-0079)], with a migration entry object-titleFormat-to-nameField. So resolveActionParams' title_format read is not merely missing a field-level leg — the canonical key it would be re-pointed at is itself deprecated in favour of nameField.
⚠️ That reading is from the sibling checkout's HEAD (5c584231), which may be ahead of the pinned 17.2.0; the unrecognized_keys rows above are from the pin. Re-measure the deprecation against the pin actually in the lockfile at dispatch time before acting on it.
Scope for whoever dispatches this
Provenance: contract review of PR #7649, comment 5550122099; earlier in-thread correction 5548853045. This card's triage (os-zhuang, 2026-09-05T02:08:34Z) predates both and inherited the eight-key list.
Generated by Claude Code
Provenance: measured while implementing objectui#7155, which inverted the read order of the lookup dialect in
@object-ui/fieldsso the spec spelling outranks the snake_case one. Filed unassigned, out of that card's declared file surface (@object-ui/fields+plugin-grid).What is measured
objectui#7155 dealt with chains that read BOTH spellings in the wrong ORDER. These two readers are the converse and strictly worse: they read the snake spelling only, so the spec-declared spelling cannot reach them at all — there is no leg to reorder.
1.
packages/plugin-charts/src/ObjectChart.tsxdisplayFieldis absent from the chain. Worse, the leg read FIRST isreference_field, which this repo's own register classifiesno-producer—packages/plugin-grid/src/relationalMetaKeys.tsrecords zero occurrences of it in the producer repo, against a control of 68 files fordisplayField.⇒ A chart grouping by a lookup whose field def declares
displayField(the only display spelling a spec-compliant author can emit, and whatgetObjectSchemaserves) falls through to the genericnameheuristic. The label is wrong in exactly the way objectui#6875 measured for the grid, and the ranked-first leg is one nothing can produce.2.
packages/app-shell/src/utils/resolveActionParams.tslines 528-541fieldhere is the resolved object-schema field. Every read is snake-only — eight keys, no camel leg on any of them (referenceTois the single exception, and it is the one key the adapter choke point genuinely stamps).FieldSchemadeclaresdisplayField,descriptionField,lookupColumns,lookupFilters,lookupPageSize,dependsOn,titleFormat; it declares none of the snake twins.⇒ An action param resolving against a real object schema loses every one of these. The camelCase values
getObjectSchemaserves are silently dropped and the param renders with defaults.Why this is the same class as objectui#7155, and why it was not fixed there
Same defect class — the renderer speaking a dialect the contract refuses — but the opposite failure mode: 7155 had two legs in the wrong order, these have one leg and it is the wrong one. Both sites are outside 7155's declared surface (
@object-ui/fieldsread chains +plugin-grid), in two other packages, so they were recorded rather than swept in.GridField,UserField,paramToField,FlowReferenceField). Here the question is which producers feed THESE two readers, and that has not been measured —resolveActionParamsreads agetObjectSchemaresult (camel), whileObjectChartreads a field def whose provenance was not traced. Adding the camel leg ahead of the snake one is the shape 7155 established, but the producer measurement should be redone per site before acting.Suggested disposition
Add the spec-declared leg, ranked FIRST, to both readers; keep the snake leg as the recorded fallback exactly as objectui#7155 did, unless a per-site producer sweep shows nothing emits it. For
ObjectChartspecifically, also consider whetherreference_fieldshould be read at all given itsno-producerverdict.domain:uiPM seat — 2026-09-05Do not dispatch this card from the eight-key list above without reading this section. The original text is left intact above (objectui#7070: a control is restated, never deleted into a vacuum). Two keys in that list are not
FieldSchema-declared, so "add the declared camel leg" is impossible for them and the follow-up scope is three keys, not eight.Measured
On the lockfile pin
@objectstack/spec@17.2.0,FieldSchema.safeParseover a minimal lookup definition:FieldSchema.shape?displayFielddescriptionFieldlookupFilterseq|ne|gt|lt|gte|lte|contains|in|notIn)idFieldunrecognized_keys[idField]titleFormatunrecognized_keys[titleFormat]id_field/title_formatunrecognized_keysControls lit in the same runs: minimal lookup def ACCEPTED;
zzz_not_a_real_keyREJECTED. Measured independently twice by two separateclaude-fable-5-1seats (the #7649 remediation and the round-3 contract review), agreeing on every row.Cross-checked by this seat directly in the
objectstacksource, which is decisive on placement and independent of both probes:packages/spec/src/data/field.zod.ts—titleFormat0 occurrences,displayField2packages/spec/src/data/object.zod.ts—titleFormat1 (line 2083),displayField0packages/spec/src/migrations/registry.tsnames the surface literally asobject.titleFormattitleFormatis an object-level key.idField's only member declaration in the spec is insideInlineGridColumnSchema(field.zod.ts:836), a different shape.One thing neither probe surfaced
The spec's own declaration at
object.zod.ts:2083carries[DEPRECATED → nameField (ADR-0079)], with a migration entryobject-titleFormat-to-nameField. SoresolveActionParams'title_formatread is not merely missing a field-level leg — the canonical key it would be re-pointed at is itself deprecated in favour ofnameField.5c584231), which may be ahead of the pinned 17.2.0; theunrecognized_keysrows above are from the pin. Re-measure the deprecation against the pin actually in the lockfile at dispatch time before acting on it.Scope for whoever dispatches this
displayField,descriptionField,lookupFilters.id_field→ objectui#7650 option A (the choke-point route). There is no declared spelling of the id key onFieldSchemain either casing, so adding anidFieldread would fossilise an undeclared spelling.title_format→ a spec-side decision, or finding(data-objectstack): the object-schema SERVE path runs no parse, so FieldSchema strictness is not evidence that a refused key cannot reach a consumer #7650 A. Not aFieldSchemaleg, and its canonical target is under an ADR-0079 deprecation.Provenance: contract review of PR #7649, comment 5550122099; earlier in-thread correction 5548853045. This card's triage (
os-zhuang, 2026-09-05T02:08:34Z) predates both and inherited the eight-key list.Generated by Claude Code