Skip to content

finding(app-shell): AuditFieldDef is a third relationship-target reader — widened carrier type + #6528's legacy spelling chain #6719

Description

@os-sales

Surfaced by the carrier census in objectui#6648 (PR #6718), deliberately left out of that PR's scope: it is a third file, and the spelling half is #6528's axis rather than #6648's.

What the census found

objectui#6528 narrowed two relationship-target resolvers to the spec spelling reference; objectui#6648 narrowed the same two to the string CARRIER. The census run for #6648 walked every reference key in both trees through the TypeScript compiler API and turned up a third reader of the same value that neither pass touched:

packages/app-shell/src/utils/auditHistoryDisplay.ts

/** Minimal structural view of an object field definition. */
export interface AuditFieldDef {
  ...
  reference_to?: string | string[];
  reference?: string | string[];
  [k: string]: unknown;
}

/** Lookup reference target when it is a single concrete object (skip polymorphic). */
function lookupTarget(def: AuditFieldDef | undefined): string | null {
  const target = def?.reference_to ?? def?.reference;
  return typeof target === 'string' && target.length > 0 ? target : null;
}

Two unfounded widenings on a type that documents itself as "a structural view of an object field definition":

  1. Carrier. FieldSchema.reference is a plain z.string(). ObjectSchema.safeParse (spec 17.2.0) REFUSES ['crm_account'] (expected string, received array) and { object: 'crm_account' } (expected string, received object). The census found ZERO producers of either carrier at the field-def key position across both trees, against 587 bare-string carriers there. string[] is a shape nothing declares and nothing emits.
  2. Spelling. reference_to ?? reference reads the legacy spelling FIRST, and reads it ahead of the canonical one. That is the exact chain objectui#6528 measured away in the two resolvers it covered: reference_to is a live key only on ObjectUI's own view/field contract, never on an object metadata document, and ObjectSchema refuses it by name.

Why this is observation-class, not a live defect

lookupTarget already narrows at RUNTIME — typeof target === 'string' && target.length > 0 — so a non-string carrier resolves to null here today. It never takes element zero, and its comment ("skip polymorphic") says the refusal is deliberate. Worth recording: when a third author met the same question the array branch in the other two resolvers was answering, they chose to REFUSE rather than guess, which is corroborating evidence for #6648's removal.

So there is no wrong answer being produced. What is left is a declared surface wider than anything that can reach it, and a spelling preference inverted relative to the spec.

What a fix would be

Filing rather than riding it along on PR #6718: the card there is explicit that its scope is two named files "in one pass", and the spelling half belongs to a different axis with its own census standard.

Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions