From afcb857880125458154db2ea4191850431f1b74a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 3 Sep 2026 07:31:17 +0000 Subject: [PATCH] =?UTF-8?q?fix(types):=20object-map=20/=20object-gantt=20?= =?UTF-8?q?=E2=80=94=20objectName=20optional=20behind=20a=20record-source?= =?UTF-8?q?=20refinement=20(objectui#6939,=20group=206=20of=208)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both mirrors in packages/types/src/zod/objectql.zod.ts REQUIRED objectName, a key both renderers read THIRD: getDataConfig in plugin-map/src/ObjectMap.tsx and plugin-gantt/src/ObjectGantt.tsx resolve records from data, then staticData, then objectName. A document authored on staticData alone drew correctly and was refused by safeValidateSchema — six catalog entries, three per component. - objectName becomes optional on both mirrors and both TS twins in the same stroke. - Each member ends in requireRecordSource: a superRefine whose issue sits at the root path, carries params.code RECORD_SOURCE_REQUIRED and names data / staticData / objectName. Presence is `!== undefined` (the ruling's wording), so the accept set only widens: objectName alone, an empty one included, still parses. - object-gantt additionally declares `data` (ViewDataSchema, the map's spelling): the resolver's FIRST read was undeclared on both faces, which would have left the refinement naming a key the validator had never heard of. - Pins: validator contract in packages/types (six catalog entries validate; negative arm checked by path / params.code / message), and render identity in each renderer's own harness with BEFORE literals measured on d88e20f55. - Docs: the two plugin pages' Schema API blocks say which of the three is required. Maintainer ruling recorded 2026-09-02 (director seat, summon #8, decision batch #8). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC --- .../6939-objectql-record-source-refinement.md | 33 ++++ content/docs/plugins/plugin-gantt.mdx | 7 +- content/docs/plugins/plugin-map.mdx | 7 +- ...ecord-source-render-identity-6939.test.tsx | 174 ++++++++++++++++++ ...bjectMap.catalogRecordSource-6939.test.tsx | 157 ++++++++++++++++ packages/plugin-map/tsconfig.test.json | 7 +- ...ctql-record-source-refinement-6939.test.ts | 151 +++++++++++++++ packages/types/src/objectql.ts | 47 ++++- packages/types/src/zod/objectql.zod.ts | 82 ++++++++- 9 files changed, 643 insertions(+), 22 deletions(-) create mode 100644 .changeset/6939-objectql-record-source-refinement.md create mode 100644 examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx create mode 100644 packages/plugin-map/src/ObjectMap.catalogRecordSource-6939.test.tsx create mode 100644 packages/types/src/__tests__/objectql-record-source-refinement-6939.test.ts diff --git a/.changeset/6939-objectql-record-source-refinement.md b/.changeset/6939-objectql-record-source-refinement.md new file mode 100644 index 0000000000..d1e5f5fe6a --- /dev/null +++ b/.changeset/6939-objectql-record-source-refinement.md @@ -0,0 +1,33 @@ +--- +'@object-ui/types': patch +--- + +Repair the `object-map` and `object-gantt` mirrors: `objectName` is optional, +and a refinement requires that at least one of `data`, `staticData`, +`objectName` is present (objectui#6939, maintainer ruling recorded 2026-09-02 — +this is one of the eight groups on that card, dispatched as its own PR per the +ruling). + +Both renderers resolve their records from one of three keys, in this order — +`getDataConfig` in `plugin-map/src/ObjectMap.tsx` and +`plugin-gantt/src/ObjectGantt.tsx`: `data`, then `staticData`, then +`objectName`. Both mirrors required `objectName` alone, so a document authored +on `staticData` drew correctly and was refused by `safeValidateSchema` — six +catalog entries, three per component. + +- **`object-map`** / **`object-gantt`**: `objectName` becomes optional on the + mirror and on the TypeScript twin in the same stroke, and each member ends in + `requireRecordSource`, whose issue sits at the root path, carries + `params.code = 'RECORD_SOURCE_REQUIRED'` and names the three keys an author + can supply. +- **`object-gantt`** additionally declares `data` (as `ViewDataSchema`, the + spelling `object-map` already used): it is the FIRST key that resolver reads + and was undeclared on both faces, which would have left the refinement naming + a key the validator had never heard of. + +**patch, not minor: the accept set only widens toward what already renders.** +Every document that validated before still validates — `objectName` alone, +including an empty one, still parses, because presence is `!== undefined` and +not the renderer's truthiness. The one shape the refinement refuses (none of +the three) was refused before too, when `objectName` was required. Documents +the renderers already draw start validating. diff --git a/content/docs/plugins/plugin-gantt.mdx b/content/docs/plugins/plugin-gantt.mdx index fe63288a4a..358c2d95ca 100644 --- a/content/docs/plugins/plugin-gantt.mdx +++ b/content/docs/plugins/plugin-gantt.mdx @@ -118,9 +118,10 @@ const schema = { ```plaintext { type: 'object-gantt', - objectName?: string, // ObjectQL object name - staticData?: Array, // Static data array - data?: ViewData, // Advanced data configuration + objectName?: string, // ObjectQL object name (read third) + staticData?: Array, // Static data array (read second) + data?: ViewData, // Advanced data configuration (read first) + // At least one of data / staticData / objectName is required gantt?: GanttConfig, // Gantt-specific configuration viewMode?: 'day' | 'week' | 'month' | 'quarter' | 'year', readOnly?: boolean // disable every edit path diff --git a/content/docs/plugins/plugin-map.mdx b/content/docs/plugins/plugin-map.mdx index 3adcddbdc1..4482a0f31b 100644 --- a/content/docs/plugins/plugin-map.mdx +++ b/content/docs/plugins/plugin-map.mdx @@ -102,9 +102,10 @@ const schema = { ```plaintext { type: 'object-map', - objectName: string, // ObjectQL object name - staticData?: Array, // Static data array - data?: ViewData, // Advanced data configuration + objectName?: string, // ObjectQL object name (read third) + staticData?: Array, // Static data array (read second) + data?: ViewData, // Advanced data configuration (read first) + // At least one of data / staticData / objectName is required filter?: Array, // Query filter, sent as $filter sort?: string | SortConfig[], // Sort, sent as $orderby map?: ObjectMapConfig, // Map-specific configuration diff --git a/examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx b/examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx new file mode 100644 index 0000000000..752954415d --- /dev/null +++ b/examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx @@ -0,0 +1,174 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * objectui#6939, the `object-map` + `object-gantt` group — the GANTT half of + * the render pin. `ObjectGanttSchema` used to require `objectName`, a key the + * renderer reads THIRD (`getDataConfig` in `plugin-gantt/src/ObjectGantt.tsx`: + * `data`, then `staticData`, then `objectName`), so the three `staticData`-only + * catalog entries below drew correctly and were refused by `safeValidateSchema`. + * The repair makes `objectName` optional behind a refinement; the validator-side + * contract is pinned in `packages/types/src/__tests__/objectql-record-source- + * refinement-6939.test.ts`, and the `object-map` tiles are pinned in + * `packages/plugin-map/src/ObjectMap.catalogRecordSource-6939.test.tsx`. + * + * ## Why the render half is the discriminating half + * + * From objectui#6318's triage: a "correction" that renders identically proves + * the SCHEMA was wrong, not the fixture. So the repair has to clear the mirror + * image of that bar — the validator's verdict must change and the renderer's + * output must NOT. The numbers in `PRE_REPAIR` were measured on `origin/main` + * at `d88e20f55`, BEFORE the mirror was touched, through THIS file's harness. + * + * ## The harness, and why it is named + * + * A bare `SchemaRenderer` is not enough here: `ObjectGantt` calls + * `useSchemaContext`, so without a `SchemaRendererProvider` the tile is the + * error boundary — 4 elements reading `Component "object-gantt" failed to + * render` — and an identity pin over THAT is the vacuous pin this file must + * not be. Measured through the provider-wrapped bare renderer below, the three + * tiles draw 407 / 354 / 436 elements. The docs-gallery harness + * (`catalog-gallery-render.test.tsx`, provider + `SidebarProvider` + a padded + * wrapper) gives different absolute counts for the same tile; identity within + * ONE harness is the claim that discriminates. `Date` is frozen because the + * chart carries a Today marker and a date-stamped export name — the pin must + * not move with the calendar. + * + * Three readings per tile, because a count alone cannot tell a swapped element + * from an equal one: element count, a tag census, and the text — the visible + * text as a literal (the chart's own `