Skip to content

Commit 2e471dc

Browse files
os-samclaude
andauthored
fix(types): narrow ObjectCalendarSchema.data to the protocol's array arm (#9348)
`ComponentPropsMap['object-calendar'].data` on `@objectstack/spec` declares `z.array(z.unknown()).optional()` — "Pre-fetched records — skips the internal fetch". Both published faces of `@object-ui/types` declared `ViewData` on the same key: a `{ provider, items }` config object, which that row refuses by kind. After objectui#8348 put the renderer on the protocol's side (decision batch #83, maintainer verbatim 8348 uses the protocol as the authority), this mirror was the lone published face still teaching the config-object spelling, so an author who validated against `@object-ui/types` got a green verdict for metadata the renderer ignores, `os validate` refuses and the save gate rejects. - TS face: `data?: ViewData` -> `data?: SpecObjectCalendarProps['data']`, DERIVED from the protocol's own row so the key cannot drift from it again. - Zod mirror: `ViewDataSchema.optional()` -> `z.array(z.unknown()).optional()`. - Requiredness unchanged on both faces, so the zod-mirror-parity ratchet is unmoved (verified with `tsc -p tsconfig.test.json`, which is the only instrument that sees that ledger's type-level reconciliation). - The `data` equality with `TsObjectGanttSchema['data']` is INVERTED rather than deleted, and both sides are named; the `staticData` and `objectName` equalities were re-checked individually and still hold. - `requireRecordSource`'s docblock says what `data` means per member: the ladder is shared, the arm is not. `object-map` / `object-gantt` keep the `ViewData` arm — neither has a `ComponentPropsMap` row, so the row governing them is this package's own. `@objectstack/spec` is untouched. Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt Co-authored-by: Claude <noreply@anthropic.com>
1 parent a984600 commit 2e471dc

5 files changed

Lines changed: 308 additions & 39 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
'@object-ui/types': minor
3+
---
4+
5+
**BREAKING — `ObjectCalendarSchema.data` narrows from the `ViewData` provider block to the protocol's ARRAY of pre-fetched records, on both published faces.**
6+
7+
`ComponentPropsMap['object-calendar'].data` on `@objectstack/spec` declares `z.array(z.unknown()).optional()`*"Pre-fetched records — skips the internal fetch"*. Both published faces of this package declared `ViewData` on the same key instead: a `{ provider, items }` config object, which that row refuses BY KIND. One key, two published shapes that refuse each other.
8+
9+
After objectui#8348 put the renderer on the protocol's side (maintainer ruling, decision batch #83, 2026-09-08, verbatim 「8348 以协议为准」), this package's mirror was the LONE published face still teaching the config-object spelling. An author who validated metadata against `@object-ui/types` got a green verdict for a document the renderer ignores, `os validate` refuses and the save gate rejects — `declared !== enforced` with the declaration on the wrong side, the shape AGENTS.md #0.1 exists to prevent. objectui#9239 brings the declaration onto the contract.
10+
11+
**What changes for authors**
12+
13+
- `ObjectCalendarSchema` (TypeScript): `data?: ViewData` becomes `data?: unknown[]`, DERIVED from the protocol's own row rather than re-spelled, so the key cannot drift from it a second time. A calendar literal carrying `data: { provider: 'value', items: [...] }` is now a compile error at `data`; an array of records compiles.
14+
- `ObjectCalendarSchema` (Zod mirror, reached by `safeValidateSchema` and so by the CLI's `validate` / `check`): `ViewDataSchema.optional()` becomes `z.array(z.unknown()).optional()`. The config object is now refused AT the key; an array is accepted.
15+
- Requiredness is unchanged — optional on both faces, as before — so the `zod-mirror-parity` ratchet is unmoved.
16+
17+
**The accept set genuinely shrinks. That is the point**, and it is a narrowing onto a contract `@objectstack/spec` already publishes, not a new dialect: every document this declaration now refuses was already refused by the protocol, by `os validate`, by the save gate and by the renderer. Nothing that renders today stops rendering because of this change — objectui#8348 is where the runtime behaviour moved.
18+
19+
**What does NOT change**
20+
21+
- `staticData` and `objectName` are untouched on this block, and so is the three-rung record-source ladder: `requireRecordSource` asks only whether a rung is PRESENT, whatever the value's kind.
22+
-`ObjectMapSchema.data` and `ObjectGanttSchema.data` stay `ViewData`. Neither block has a `ComponentPropsMap` row, so the published row that governs them is this package's own — they are not following, and the type-level equality that used to bind the calendar's `data` to the gantt's is now pinned as a DIFFERENCE rather than deleted.
23+
-`@objectstack/spec` itself is not touched.
24+
25+
Refs: objectui#9239 · objectui#8348 (the ruling and the renderer half) · objectui#7313 (which declared this key, in the provider-block arm) · objectui#4631

content/docs/plugins/plugin-calendar.mdx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,12 @@ const schema: ObjectCalendarSchema = {
242242
type: 'object-calendar',
243243
objectName?: string, // ObjectQL object name
244244
staticData?: Array<any>, // Static data array
245-
data?: Array<any>, // Pre-fetched records, drawn in place of the
245+
data?: Array<unknown>, // Pre-fetched records, drawn in place of the
246246
// calendar's own query. An ARRAY — this block's
247247
// published row refuses the `{ provider, items }`
248-
// config object (objectui#8348)
248+
// config object (objectui#8348). `@object-ui/types`
249+
// declares it as that array too since
250+
// objectui#9239, derived from the protocol's row
249251
calendar?: CalendarConfig, // Calendar-specific configuration
250252
filter?: ViewFilterRule[], // Query filter, lowered to $filter
251253
sort?: SortConfig[], // Query sort, lowered to $orderby
@@ -366,10 +368,19 @@ here. `object-calendar`'s published `data` row is an **array of pre-fetched
366368
records**, so the config object is refused by kind: `os validate` and the save
367369
gate reject it, and as of that card the renderer does too.
368370

369-
That is a behaviour change for stored documents. A calendar written that way no
370-
longer draws those rows; the record-source ladder falls past `data` to
371-
`staticData`, then to `objectName`, so it queries its object instead — or draws
372-
nothing when it names neither.
371+
Since **objectui#9239** the `@object-ui/types` declaration refuses it as well —
372+
both the `ObjectCalendarSchema` interface and the zod mirror `safeValidateSchema`
373+
runs. Until that card this package was the one published face that still
374+
accepted the config object, so a document validated *here* could pass while every
375+
other surface rejected it; the annotated examples on this page are checked
376+
against the narrowed declaration.
377+
378+
That is a behaviour change for stored documents, and a **breaking narrowing** of
379+
the authoring type. A calendar written that way no longer draws those rows; the
380+
record-source ladder falls past `data` to `staticData`, then to `objectName`, so
381+
it queries its object instead — or draws nothing when it names neither. In
382+
TypeScript the same document is now a compile error at `data` rather than a
383+
silent pass.
373384

374385
Read from the database with the **Object Provider** above (`objectName`), pass
375386
events you already hold with the **Value Provider** (`staticData`), or hand the

0 commit comments

Comments
 (0)