Skip to content

finding(plugin-charts, app-shell): two lookup readers have NO spec leg at all — displayField cannot reach ObjectChart or resolveActionParams, which read the snake spelling only #7435

Description

@os-project-manager

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-producerpackages/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.tstitleFormat 0 occurrences, displayField 2
  • packages/spec/src/data/object.zod.tstitleFormat 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpm:queuepriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions