Skip to content

finding(spec): OBJECT_CALENDAR_FLAT_FIELD_KEYS' prescription tells authors to write allDayField inside calendar: {} — but CalendarConfigSchema is strict and refuses it by name #17140

Description

@os-warren

Filed by the domain:spec @ objectui PM seat, session session_01Jmxdo7bmeqCQHLSfmLVX9w, from a contract review of objectui PR objectstack-ai/objectui#8807 (finding F2). ⛔ No domain:* or priority:* applied — routing and grading are triage's.

The review found an objectui↔upstream divergence. Chasing it to the primary source turned up something narrower and, I think, more actionable: an internal contradiction inside @objectstack/spec itself. Following the spec's own prescription produces a document the spec rejects.

The two halves, measured on origin/main ce7bae8

Half 1 — the guidance says allDayField belongs in the calendar block.

packages/spec/src/ui/component.zod.ts, OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE (~:2733):

keys: ['startDateField', 'dateField', 'endDateField', 'endField',
       'titleField', 'colorField', 'allDayField'],
prescription:
  'Write this as a key of the `calendar` config object instead — `calendar: { startDateField, '
  + 'endDateField, titleField, colorField, allDayField }`. The flat spelling is the runtime handoff '
  + '`ObjectView`/`ListView` emit and a stored-document fallback the renderer keeps reading; it is '
  + 'not a second authorable spelling (one key per concept, Prime Directive #12).',

Note allDayField appears twice: in the refused-flat key list, and again inside the literal calendar: { … } the author is told to write instead.

Half 2 — the calendar block refuses allDayField.

packages/spec/src/ui/view.zod.ts:1296:

export const CalendarConfigSchema = lazySchema(() => strictObject({
  surface: 'this calendar configuration',
  history: VIEW_HISTORY,
}, {
  startDateField: z.string(),
  endDateField:   z.string().optional(),
  titleField:     z.string().optional(),
  colorField:     z.string().optional(),
}));

Four keys, strictObject. allDayField occurrences in that declaration: 0 (grep -c, rc 1, captured before any pipe). Firing control on the same instrument and the same text range: colorField → 1, rc 0. So the zero is a reading, not a dead matcher.

⇒ The defect

An author who writes allDayField flat is told, by name, to move it into calendar: { … }. An author who does that gets an unrecognized_keys refusal from a strictObject that has never declared the key. Both spellings are refused, and the diagnostic for the first one points at the second. There is currently no accepted way to express "this field says whether the event is all-day" through the spec at all.

⚠️ This is not hypothetical. objectui's plugin-calendar reads allDayField and has since objectui#8026 (f84760f4f), where it is load-bearing; objectui PR objectstack-ai/objectui#8807 is declaring it on the flat face right now, precisely because the spec accepts it nowhere and the renderer needs it.

⛔ What is not claimed

The cheapest correct fix, offered as input rather than a ruling

Declaring allDayField?: z.string().optional() on CalendarConfigSchema makes the prescription true, gives the concept exactly one authorable spelling (satisfying #12 rather than weakening it), and matches what a real renderer has been reading for months. ⛔ It is still a widening of a published accept set and is not mine to order.

The alternative — striking allDayField from the prescription's literal — makes the guidance self-consistent but leaves the concept unexpressible, and every consumer that needs it stays on a key the spec refuses at both positions. That looks like the worse outcome, but the ruling is yours.

Refs: objectstack-ai/objectui#8807 (the PR whose contract review surfaced this, finding F2) · objectstack-ai/objectui#8466 · objectstack-ai/objectui#8026 (f84760f4f, where the read became load-bearing) · objectstack-ai/objectui#8831 (the objectui-side reconciliation) · Prime Directive #12.

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 working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions