Skip to content

finding(core): resolveRecordSourceConfig's parameter declares data?: ViewData, which contradicts its own dataArm: 'array' contract #9473

Description

@os-sam

Found while implementing objectui#8651 (PR #9471). Filed unassigned and not fixed there — that card's dispatch bounds its file surface to packages/plugin-calendar/src/ and packages/types/src/, and packages/core/ is outside it.

⛔ Filed unassigned, not claiming. ⛔ No domain:*, priority or type applied — routing and grading are triage's.

What

packages/core/src/utils/record-source.ts declares the shared record-source ladder as:

export function resolveRecordSourceConfig(
  schema: {
    objectName?: string;
    data?: ViewData;
    staticData?: any[];
  },
  dataArm: RecordSourceDataArm,
): ViewData | null

The dataArm parameter exists precisely because blocks declare data differently — the function's own docblock says so: "The arm the CALLING BLOCK's published data row declares. Required: there is no repo-wide default, because the answer differs per block and a default is how the second de-facto contract got in."

And its rung-1 predicate takes unknown, not ViewData:

function authoredDataIsOnTheDeclaredArm(authored: unknown, arm: RecordSourceDataArm): boolean {
  if (!authored) return false;
  if (arm === 'array') return Array.isArray(authored);
  if (arm === 'view-data') return !Array.isArray(authored);
  return true;
}

So the runtime contract admits an ARRAY on the 'array' arm, while the parameter type admits only ViewData, which has no array member. The declaration contradicts the contract the same function documents and implements.

Why nothing caught it

object-calendar is the block on the 'array' arm (objectui#9239, ruling objectui#8348 — ObjectCalendarSchema.data derives ComponentPropsMap['object-calendar'].data, which is an array). Its caller type-checked anyway because ObjectCalendarComponentProps.schema was the union ObjectGridSchema | CalendarSchema, and ObjectGridSchema.data IS ViewData. The union satisfied the parameter while saying something the calendar block does not mean.

objectui#8651 removes that union, and the contradiction surfaces immediately.

Measured

On origin/main e3cb47624e, with ObjectCalendarComponentProps.schema re-pointed at the published ObjectCalendarSchema and the call left as it was, pnpm exec tsc --noEmit in packages/plugin-calendar exits 2:

src/ObjectCalendar.tsx(386,62): error TS2345: Argument of type 'ObjectCalendarSchema' is not
assignable to parameter of type '{ objectName?: string; data?: ...; staticData?: any[]; }'.
  Types of property 'data' are incompatible.
    Type 'unknown[] | undefined' is not assignable to type '{ provider: "object"; object: string; } | ...'

Suggested shape, not a ruling

Widen the parameter's data to the union of the arms RecordSourceDataArm enumerates, so the signature says what authoredDataIsOnTheDeclaredArm already decides. ⛔ That is a suggestion for whoever takes this; the contract question is theirs.

A second, smaller half in the same file

Two docblock passages in record-source.ts describe the calendar caller in terms of the union objectui#8651 removes — "because its parameter is the union ObjectGridSchema | CalendarSchema and CalendarSchema declares neither data nor staticData". The same sentence is carried in packages/core/src/utils/__tests__/record-source-config.behaviourNeutrality-7632.test.ts. Both go stale when that PR lands and are worth correcting in the same stroke as the signature.

Refs

objectui#8651 (the card that surfaced it) · objectui#9239 / objectui#8348 (the arm ruling) · objectui#7632.

Raised by an automated development seat working objectui#8651; session reference session_01L5xpA5q533BgTTNADibEFt. Generated with 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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions