Skip to content

finding(core,app-shell): after #6528 the relationship-target resolvers still accept array / { object } CARRIERS the spec refuses — same leniency, second axis #6648

Description

@os-sales

Surfaced by the census in objectui#6528, deliberately left out of that PR's scope.

objectui#6528 narrowed both relationship-target resolvers to the single spec SPELLING reference. It did not touch the CARRIER — the shape the value may take — because that is a separate axis and its own census was not in the charter. Measuring it turns up the same class of unfounded leniency.

Measurement

@objectstack/spec 17.2.0, ObjectSchema.safeParse, one lookup field, three carriers for the canonical reference key:

carrier verdict
reference: 'crm_account' ACCEPTED (positive control — parses green, value survives)
reference: ['crm_account'] REFUSED — invalid_type: Invalid input: expected string, received array
reference: { object: 'crm_account' } REFUSED — invalid_type: Invalid input: expected string, received object

FieldSchema.reference is a plain string. Both resolvers nonetheless still branch on all three:

  • packages/core/src/utils/chart-series.tsresolveRelationshipTarget
  • packages/app-shell/src/views/metadata-admin/inspectors/useDatasetFields.tsresolveReferenceTo
if (typeof raw === 'string' && raw) return raw;
if (Array.isArray(raw) && typeof raw[0] === 'string') return raw[0];
if (raw && typeof raw === 'object') { /* { object } */ }

The array branch additionally makes a silent product decision: given a multi-target value it returns raw[0] and discards the rest.

Why it was not cut in #6528

Scope discipline, and one unfinished measurement. The spelling census had a clean population count behind it (445 of 565 lookup / master_detail defs in the framework tree spell the key reference); the carrier axis does not yet. A grep for producers emitting an array carrier returned zero in both trees, but that zero has not been run down to the same standard — in particular whether any polymorphic / multi-target lookup is intended to carry a list. Cutting on an unfinished census is exactly what #6528 was filed to stop.

The question to settle

Same one AGENTS.md #0.1 asks: a lenient consumer is where a wrong producer hides. If nothing produces an array or { object } carrier, both branches are dead code that reads like a measurement and should go, in both files in one pass (they must not diverge). If something DOES produce one, that is a producer-side defect or a spec question about multi-target lookups — fix it there, not by keeping the tolerant read.

Whoever takes this: the refusal pins added by objectui#6528 (refuses the legacy spelling ...) are the pattern to extend, and the two carrier assertions currently live in useDatasetFields.test.ts and chart-series.test.ts as green pins that would need the same triage — updated with the helper, not preserved as cover.

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatchedpriority:p2

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions