From c7ea4147eac0296eec28dda2bd4d0b2e3b12d6a4 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 13:48:45 +0000 Subject: [PATCH] refactor(types)!: rename the declarative Kanban trio, leaving the bare names to plugin-kanban (objectui#6172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `KanbanSchema` / `KanbanColumn` / `KanbanCard` were declared twice with disagreeing shapes — once in `@object-ui/types` and once in `@object-ui/plugin-kanban`. The 2026-08-31 maintainer ruling (决裁批 #14, option A) settled the authority: the plugin keeps the bare names, because all four registered kanban renderers consume that dialect, and objectui#6086 measured that auto-importing the copy no renderer reads produces a confident empty board rather than an abstention. The `@object-ui/types` trio becomes `DeclarativeKanbanSchema` / `DeclarativeKanbanColumn` / `DeclarativeKanbanCard`, and its Zod mirror follows the package's `Schema` convention. Pure rename: no member, no optionality and no accept/reject behaviour moves. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3 --- .changeset/6172-kanban-trio-rename.md | 45 +++++++++++++++++++ content/docs/api/index.md | 2 +- content/docs/api/schema-reference.md | 8 ++-- packages/types/README.md | 2 +- .../types/examples/zod-validation-example.ts | 4 +- ...ent-docs-retired-handler-keys-7340.test.ts | 4 +- .../handler-keys-json-refusal-6124.test.ts | 20 ++++----- .../src/__tests__/zod-mirror-parity.test.ts | 18 ++++---- packages/types/src/complex.ts | 37 +++++++++++---- packages/types/src/index.ts | 6 +-- packages/types/src/registry.ts | 11 ++++- packages/types/src/zod/README.md | 2 +- packages/types/src/zod/complex.zod.ts | 12 ++--- packages/types/src/zod/index.zod.ts | 6 +-- ...e-authority-per-exported-name-6273.test.ts | 29 ++++++------ 15 files changed, 140 insertions(+), 66 deletions(-) create mode 100644 .changeset/6172-kanban-trio-rename.md diff --git a/.changeset/6172-kanban-trio-rename.md b/.changeset/6172-kanban-trio-rename.md new file mode 100644 index 0000000000..6d08f05e39 --- /dev/null +++ b/.changeset/6172-kanban-trio-rename.md @@ -0,0 +1,45 @@ +--- +'@object-ui/types': minor +--- + +One authority for `KanbanSchema` / `KanbanColumn` / `KanbanCard`: the bare names +now belong to `@object-ui/plugin-kanban` (objectui#6172, closing the +cross-package half of objectui#6155). + +**Breaking, deliberately — six published names are removed from +`@object-ui/types`.** Per this repo's own rule a breaking change ships `minor`, +with the break spelled out here. + +| removed from | old name | new name | +| --- | --- | --- | +| `@object-ui/types` | `KanbanSchema` | `DeclarativeKanbanSchema` | +| `@object-ui/types` | `KanbanColumn` | `DeclarativeKanbanColumn` | +| `@object-ui/types` | `KanbanCard` | `DeclarativeKanbanCard` | +| `@object-ui/types/zod` | `KanbanSchema` | `DeclarativeKanbanSchema` | +| `@object-ui/types/zod` | `KanbanColumnSchema` | `DeclarativeKanbanColumnSchema` | +| `@object-ui/types/zod` | `KanbanCardSchema` | `DeclarativeKanbanCardSchema` | + +Nothing else moved: every member, every optionality and the Zod mirror's whole +accept/reject behaviour are byte-for-byte the shape they were. `SchemaRegistry` +still maps `'kanban'`, `ComplexSchema` still carries the arm, and +`safeValidateSchema` accepts and refuses exactly what it did before. + +**Migration.** `import type { KanbanSchema } from '@object-ui/types'` becomes +either of two things, and which one you want is the whole point of the rename: + +- authoring a board that a **registered renderer** will draw — import the bare + name from `@object-ui/plugin-kanban`, which is unchanged; +- annotating or validating the **declarative** shape `@object-ui/types` mirrors + in Zod — import `DeclarativeKanbanSchema` (or the Zod + `DeclarativeKanbanSchema` from `@object-ui/types/zod`). + +**Why this direction.** The two declarations were structurally unrelated +dialects sharing three names, and `@object-ui/types` is the declared +zero-workspace-dependency bottom layer, so it cannot re-point at a plugin — +convergence had to remove a name from one side or the other. All four +registered kanban renderers (`kanban`, `kanban-ui`, `kanban-enhanced`, +`object-kanban`) consume the plugin's dialect and none consumes this one, and +objectui#6086 measured what happens when the bare name is the copy no renderer +reads: an IDE or agent auto-import silently authors a board that renders +nothing — a confident empty board rather than an abstention. So the surviving +bare name is the one a renderer honours. diff --git a/content/docs/api/index.md b/content/docs/api/index.md index 39825c0079..d1e4316fcb 100644 --- a/content/docs/api/index.md +++ b/content/docs/api/index.md @@ -19,5 +19,5 @@ Complete reference for every ObjectUI schema type with annotated JSON examples c - **Data Display** — `TableSchema`, `ChartSchema`, `TreeViewSchema` - **CRUD** — `ActionSchema`, `DetailSchema`, `CRUDDialogSchema` - **ObjectQL** — `ObjectGridSchema`, `ObjectFormSchema`, `ObjectViewSchema` -- **Complex** — `KanbanSchema`, `DashboardSchema`, `CalendarViewSchema` +- **Complex** — `DeclarativeKanbanSchema`, `DashboardSchema`, `CalendarViewSchema` - **Views** — `DetailViewSchema`, `ViewSwitcherSchema` diff --git a/content/docs/api/schema-reference.md b/content/docs/api/schema-reference.md index 1f7680b387..5f36bd0247 100644 --- a/content/docs/api/schema-reference.md +++ b/content/docs/api/schema-reference.md @@ -882,7 +882,7 @@ A complete object management interface combining grid, form, search, filters, an ## Complex Schemas -### KanbanSchema +### DeclarativeKanbanSchema A drag-and-drop Kanban board with columns and cards. @@ -920,7 +920,7 @@ A drag-and-drop Kanban board with columns and cards. | Property | Type | Description | |----------|------|-------------| -| `columns` | `KanbanColumn[]` | **Required.** Board columns, each with `id`, `title`, `color`, and `cards`. | +| `columns` | `DeclarativeKanbanColumn[]` | **Required.** Board columns, each with `id`, `title`, `color`, and `cards`. | | `draggable` | `boolean` | Enable drag-and-drop between columns. | | `onCardMove` | `function` | Callback when a card is moved: `(cardId, fromColumn, toColumn, position)`. | | `onCardClick` | `function` | Callback when a card is clicked. | @@ -1190,7 +1190,7 @@ A toggle control that switches between different view types (list, grid, kanban, | `storageKey` | `string` | Storage key for persisting the preference. | | `onViewChange` | `string` | Expression or callback invoked on view change. | -**Related:** [ObjectViewSchema](#objectviewschema), [KanbanSchema](#kanbanschema), [CalendarViewSchema](#calendarviewschema) +**Related:** [ObjectViewSchema](#objectviewschema), [DeclarativeKanbanSchema](#declarativekanbanschema), [CalendarViewSchema](#calendarviewschema) --- @@ -1265,7 +1265,7 @@ import type { ActionSchema, DetailSchema } from '@object-ui/types'; import type { ObjectGridSchema, ObjectFormSchema, ObjectViewSchema } from '@object-ui/types'; // Complex -import type { KanbanSchema, DashboardComponentSchema, CalendarViewSchema } from '@object-ui/types'; +import type { DeclarativeKanbanSchema, DashboardComponentSchema, CalendarViewSchema } from '@object-ui/types'; // Views import type { DetailViewSchema, ViewSwitcherSchema } from '@object-ui/types'; diff --git a/packages/types/README.md b/packages/types/README.md index cf887d4eb0..c8f086faca 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -195,7 +195,7 @@ Menus and navigation: Advanced composite components: -- `KanbanSchema` - Kanban board +- `DeclarativeKanbanSchema` - Kanban board - `CalendarViewSchema` - Calendar with events - `FilterBuilderSchema` - Advanced filter builder - `CarouselSchema` - Image/content carousel diff --git a/packages/types/examples/zod-validation-example.ts b/packages/types/examples/zod-validation-example.ts index d7edc83dc4..a5a147f38d 100644 --- a/packages/types/examples/zod-validation-example.ts +++ b/packages/types/examples/zod-validation-example.ts @@ -18,7 +18,7 @@ import { FormSchema, CardSchema, DataTableSchema, - KanbanSchema, + DeclarativeKanbanSchema, } from '../src/zod/index.zod'; // The failure accessor below is `error.issues`. Zod 4 removed the `.errors` @@ -161,7 +161,7 @@ const kanbanExample = { draggable: true, }; -const kanbanResult = KanbanSchema.safeParse(kanbanExample); +const kanbanResult = DeclarativeKanbanSchema.safeParse(kanbanExample); console.log('Kanban validation:', kanbanResult.success ? 'PASSED ✓' : 'FAILED ✗'); if (!kanbanResult.success) { console.error('Kanban errors:', kanbanResult.error.issues); diff --git a/packages/types/src/__tests__/component-docs-retired-handler-keys-7340.test.ts b/packages/types/src/__tests__/component-docs-retired-handler-keys-7340.test.ts index 71a9a6b362..0c047fbccd 100644 --- a/packages/types/src/__tests__/component-docs-retired-handler-keys-7340.test.ts +++ b/packages/types/src/__tests__/component-docs-retired-handler-keys-7340.test.ts @@ -253,8 +253,8 @@ const describeRow = (r: DocRow): string => `${r.page}:${r.line} ${r.owner}.${r.k /** Runtime-slot rows measured present on this tree — the blanket-sweep control. */ const CONTROL = [ - { page: 'api/schema-reference.md', owner: 'KanbanSchema', key: 'onCardMove' }, - { page: 'api/schema-reference.md', owner: 'KanbanSchema', key: 'onCardClick' }, + { page: 'api/schema-reference.md', owner: 'DeclarativeKanbanSchema', key: 'onCardMove' }, + { page: 'api/schema-reference.md', owner: 'DeclarativeKanbanSchema', key: 'onCardClick' }, { page: 'components/basic/pagination.mdx', owner: 'PaginationSchema', key: 'onPageChange' }, { page: 'components/data-display/tree-view.mdx', owner: 'TreeViewSchema', key: 'onNodeClick' }, { page: 'components/form/button.mdx', owner: 'ButtonSchema', key: 'onClick' }, diff --git a/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts b/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts index 062bfe6333..a1d9b23ad0 100644 --- a/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts +++ b/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts @@ -83,7 +83,7 @@ import { CarouselSchema as CarouselZod, ChatbotSchema as ChatbotZod, FilterBuilderSchema as FilterBuilderZod, - KanbanSchema as KanbanZod, + DeclarativeKanbanSchema as KanbanZod, } from '../zod/complex.zod'; import { AlertSchema as AlertZod, @@ -139,7 +139,7 @@ import type { CarouselSchema, ChatbotSchema, FilterBuilderSchema, - KanbanSchema, + DeclarativeKanbanSchema, } from '../complex'; import type { AlertSchema, DataTableSchema, ListItem, TreeViewSchema } from '../data-display'; import type { AccordionSchema, CollapsibleSchema, ToggleGroupSchema } from '../disclosure'; @@ -214,8 +214,8 @@ const objectOf = (mirror: z.ZodType, key: string): z.ZodObject => * `toFormControlDomProps` whitelist, card's ``). */ const RUNTIME_SLOT: readonly Site[] = [ - ['complex.zod.ts', 'KanbanSchema', 'onCardMove', KanbanZod], - ['complex.zod.ts', 'KanbanSchema', 'onCardClick', KanbanZod], + ['complex.zod.ts', 'DeclarativeKanbanSchema', 'onCardMove', KanbanZod], + ['complex.zod.ts', 'DeclarativeKanbanSchema', 'onCardClick', KanbanZod], ['complex.zod.ts', 'CalendarViewSchema', 'onViewChange', CalendarViewZod], ['complex.zod.ts', 'FilterBuilderSchema', 'onChange', FilterBuilderZod], ['complex.zod.ts', 'ChatbotSchema', 'onError', ChatbotZod], @@ -265,8 +265,8 @@ const RUNTIME_SLOT: readonly Site[] = [ * from the declared `(value: string) => void`, not a consumer of it. */ const RETIRED: readonly Site[] = [ - ['complex.zod.ts', 'KanbanSchema', 'onColumnAdd', KanbanZod], - ['complex.zod.ts', 'KanbanSchema', 'onCardAdd', KanbanZod], + ['complex.zod.ts', 'DeclarativeKanbanSchema', 'onColumnAdd', KanbanZod], + ['complex.zod.ts', 'DeclarativeKanbanSchema', 'onCardAdd', KanbanZod], ['complex.zod.ts', 'CarouselSchema', 'onSlideChange', CarouselZod], ['complex.zod.ts', 'ChatbotSchema', 'onSendMessage', ChatbotZod], ['data-display.zod.ts', 'AlertSchema', 'onDismiss', AlertZod], @@ -480,8 +480,8 @@ type KeepsFunction = [Extract, (...args: never[]) => unknown>] : true; export type assertionRetiredKeysAreTombstoned = [ - Expect>, - Expect>, + Expect>, + Expect>, Expect>, Expect>, Expect>, @@ -505,8 +505,8 @@ export type assertionRetiredKeysAreTombstoned = [ ]; export type assertionRuntimeSlotsKeepTheirFunctionType = [ - Expect>, - Expect>, + Expect>, + Expect>, Expect>, Expect>, Expect>, diff --git a/packages/types/src/__tests__/zod-mirror-parity.test.ts b/packages/types/src/__tests__/zod-mirror-parity.test.ts index 4175106948..bc125618fe 100644 --- a/packages/types/src/__tests__/zod-mirror-parity.test.ts +++ b/packages/types/src/__tests__/zod-mirror-parity.test.ts @@ -151,7 +151,7 @@ import type { z } from 'zod'; import { AppActionSchema, AppComponentSchema, NavigationAreaSchema } from '../zod/app.zod.js'; import { BaseSchema, ComponentConfigSchema, ComponentInputSchema, ComponentMetaSchema, KeyedI18nLabelSchema } from '../zod/base.zod.js'; -import { CalendarEventSchema, CalendarViewSchema, CarouselItemSchema, CarouselSchema, ChatbotSchema, ChatMessageSchema, ChatMessageSourceSchema, ChatToolInvocationSchema, DashboardComponentSchema, DashboardConfigSchema, DashboardWidgetConfigSchema, DashboardWidgetLayoutSchema, DashboardWidgetSchema, FilterBuilderSchema, FilterFieldSchema, KanbanCardSchema, KanbanColumnSchema, KanbanSchema } from '../zod/complex.zod.js'; +import { CalendarEventSchema, CalendarViewSchema, CarouselItemSchema, CarouselSchema, ChatbotSchema, ChatMessageSchema, ChatMessageSourceSchema, ChatToolInvocationSchema, DashboardComponentSchema, DashboardConfigSchema, DashboardWidgetConfigSchema, DashboardWidgetLayoutSchema, DashboardWidgetSchema, FilterBuilderSchema, FilterFieldSchema, DeclarativeKanbanCardSchema, DeclarativeKanbanColumnSchema, DeclarativeKanbanSchema } from '../zod/complex.zod.js'; import { ActionCallbackSchema, CRUDDialogSchema, DetailSchema } from '../zod/crud.zod.js'; import { AlertSchema, AvatarSchema, BadgeSchema, BarChartSchema, ChartDataSeriesSchema, ChartSchema, DataTableSchema, HtmlSchema, KbdSchema, ListItemSchema, ListSchema, MarkdownSchema, StaticTableColumnSchema, StatisticSchema, TableColumnSchema, TableSchema, TimelineEventSchema, TimelineSchema, TreeViewSchema } from '../zod/data-display.zod.js'; import { AccordionItemSchema, AccordionSchema, CollapsibleSchema, ToggleGroupItemSchema, ToggleGroupSchema } from '../zod/disclosure.zod.js'; @@ -166,7 +166,7 @@ import { DetailViewFieldSchema, DetailViewSchema, DetailViewSectionSchema, Detai import type { AppAction as Ts_AppAction, AppComponentSchema as Ts_AppComponentSchema, NavigationArea as Ts_NavigationArea } from '../app'; import type { BaseSchema as Ts_BaseSchema, ComponentConfig as Ts_ComponentConfig, ComponentInput as Ts_ComponentInput, ComponentMeta as Ts_ComponentMeta, KeyedI18nLabel as Ts_KeyedI18nLabel } from '../base'; -import type { CalendarEvent as Ts_CalendarEvent, CalendarViewSchema as Ts_CalendarViewSchema, CarouselItem as Ts_CarouselItem, CarouselSchema as Ts_CarouselSchema, ChatbotSchema as Ts_ChatbotSchema, ChatMessage as Ts_ChatMessage, ChatMessageSource as Ts_ChatMessageSource, ChatToolInvocation as Ts_ChatToolInvocation, DashboardComponentSchema as Ts_DashboardComponentSchema, DashboardWidgetLayout as Ts_DashboardWidgetLayout, DashboardWidgetSchema as Ts_DashboardWidgetSchema, FilterBuilderSchema as Ts_FilterBuilderSchema, FilterField as Ts_FilterField, KanbanCard as Ts_KanbanCard, KanbanColumn as Ts_KanbanColumn, KanbanSchema as Ts_KanbanSchema } from '../complex'; +import type { CalendarEvent as Ts_CalendarEvent, CalendarViewSchema as Ts_CalendarViewSchema, CarouselItem as Ts_CarouselItem, CarouselSchema as Ts_CarouselSchema, ChatbotSchema as Ts_ChatbotSchema, ChatMessage as Ts_ChatMessage, ChatMessageSource as Ts_ChatMessageSource, ChatToolInvocation as Ts_ChatToolInvocation, DashboardComponentSchema as Ts_DashboardComponentSchema, DashboardWidgetLayout as Ts_DashboardWidgetLayout, DashboardWidgetSchema as Ts_DashboardWidgetSchema, FilterBuilderSchema as Ts_FilterBuilderSchema, FilterField as Ts_FilterField, DeclarativeKanbanCard as Ts_KanbanCard, DeclarativeKanbanColumn as Ts_KanbanColumn, DeclarativeKanbanSchema as Ts_KanbanSchema } from '../complex'; import type { DashboardConfig as Ts_DashboardConfig, DashboardWidgetConfig as Ts_DashboardWidgetConfig } from '../designer'; import type { ActionCallback as Ts_ActionCallback, CRUDDialogSchema as Ts_CRUDDialogSchema, DetailSchema as Ts_DetailSchema } from '../crud'; import type { AlertSchema as Ts_AlertSchema, AvatarSchema as Ts_AvatarSchema, BadgeSchema as Ts_BadgeSchema, BarChartSchema as Ts_BarChartSchema, ChartDataSeries as Ts_ChartDataSeries, ChartSchema as Ts_ChartSchema, DataTableSchema as Ts_DataTableSchema, HtmlSchema as Ts_HtmlSchema, KbdSchema as Ts_KbdSchema, ListItem as Ts_ListItem, ListSchema as Ts_ListSchema, MarkdownSchema as Ts_MarkdownSchema, StaticTableColumn as Ts_StaticTableColumn, StatisticSchema as Ts_StatisticSchema, TableColumn as Ts_TableColumn, TableSchema as Ts_TableSchema, TimelineEvent as Ts_TimelineEvent, TimelineSchema as Ts_TimelineSchema, TreeViewSchema as Ts_TreeViewSchema, BreadcrumbItem as Ts_BreadcrumbItem, BreadcrumbSchema as Ts_BreadcrumbSchema } from '../data-display'; @@ -387,9 +387,9 @@ const MIRRORS = { 'complex.zod.ts#DashboardWidgetSchema': DashboardWidgetSchema, 'complex.zod.ts#FilterBuilderSchema': FilterBuilderSchema, 'complex.zod.ts#FilterFieldSchema': FilterFieldSchema, - 'complex.zod.ts#KanbanCardSchema': KanbanCardSchema, - 'complex.zod.ts#KanbanColumnSchema': KanbanColumnSchema, - 'complex.zod.ts#KanbanSchema': KanbanSchema, + 'complex.zod.ts#DeclarativeKanbanCardSchema': DeclarativeKanbanCardSchema, + 'complex.zod.ts#DeclarativeKanbanColumnSchema': DeclarativeKanbanColumnSchema, + 'complex.zod.ts#DeclarativeKanbanSchema': DeclarativeKanbanSchema, 'crud.zod.ts#ActionCallbackSchema': ActionCallbackSchema, 'crud.zod.ts#CRUDDialogSchema': CRUDDialogSchema, 'crud.zod.ts#DetailSchema': DetailSchema, @@ -545,9 +545,9 @@ interface Declared { 'complex.zod.ts#DashboardWidgetSchema': Ts_DashboardWidgetSchema; 'complex.zod.ts#FilterBuilderSchema': Ts_FilterBuilderSchema; 'complex.zod.ts#FilterFieldSchema': Ts_FilterField; - 'complex.zod.ts#KanbanCardSchema': Ts_KanbanCard; - 'complex.zod.ts#KanbanColumnSchema': Ts_KanbanColumn; - 'complex.zod.ts#KanbanSchema': Ts_KanbanSchema; + 'complex.zod.ts#DeclarativeKanbanCardSchema': Ts_KanbanCard; + 'complex.zod.ts#DeclarativeKanbanColumnSchema': Ts_KanbanColumn; + 'complex.zod.ts#DeclarativeKanbanSchema': Ts_KanbanSchema; 'crud.zod.ts#ActionCallbackSchema': Ts_ActionCallback; 'crud.zod.ts#CRUDDialogSchema': Ts_CRUDDialogSchema; 'crud.zod.ts#DetailSchema': Ts_DetailSchema; @@ -763,7 +763,7 @@ interface KnownDrift { /** DISJOINT vocabularies: TS declares `is_empty`/`is_not_empty`, the mirror declares `is_null`/`is_not_null`. One of the two is dead; which one is a ruling. */ 'complex.zod.ts#FilterFieldSchema': 'operators'; /** RUNTIME SLOT (objectui#6124) ×2: `plugin-kanban` forwards `onCardMove` / `onCardClick` off `schema.*` into the board. (`onColumnAdd` / `onCardAdd` are NOT here: nothing reads them, so both faces retire them — `?: never` meets the refusal arm and the pair does not drift on those keys.) */ - 'complex.zod.ts#KanbanSchema': 'onCardMove' | 'onCardClick'; + 'complex.zod.ts#DeclarativeKanbanSchema': 'onCardMove' | 'onCardClick'; /** * RUNTIME SLOT (objectui#7344): `register('detail', DetailView)` — `DetailView`'s * `handleBack` calls `onBack()` when set. The mirror was `z.any()` (wider than diff --git a/packages/types/src/complex.ts b/packages/types/src/complex.ts index 17fe955713..b0d9db278c 100644 --- a/packages/types/src/complex.ts +++ b/packages/types/src/complex.ts @@ -23,9 +23,30 @@ import type { import type { BaseSchema, SchemaNode } from './base.js'; /** - * Kanban column + * Kanban column — the DECLARATIVE (authoring / validation) face. + * + * ## Why the name carries a `Declarative` prefix (objectui#6172) + * + * This trio and `@object-ui/plugin-kanban`'s `KanbanCard` / `KanbanColumn` / + * `KanbanSchema` were two declarations of one set of names, in two dialects. + * The 2026-08-31 maintainer ruling (决裁批 #14, option A) settled the authority: + * **the plugin KEEPS the bare names**, because those are what all four + * registered kanban renderers (`kanban`, `kanban-ui`, `kanban-enhanced`, + * `object-kanban`) consume, and objectui#6086 measured the failure mode of + * getting that backwards — an IDE or agent auto-importing the bare name picks + * whichever copy sorts first, and the wrong one produces a **confident empty + * board** instead of an abstention. So the surviving bare name has to be the + * one a renderer honours. + * + * What survives here is the face this package really serves: the authoring + * shape and its Zod mirror (`zod/complex.zod.ts`), which is the `'kanban'` arm + * of `ComplexSchema` → `AnyComponentSchema` → `safeValidateSchema` and so + * validates every authored `{ "type": "kanban" }` document the CLI's + * `validate` / `check` commands see. Renaming rather than retiring was the + * ruled outcome; ⛔ do not re-point these at the plugin — `@object-ui/types` is + * the zero-workspace-dependency bottom layer and cannot depend on a plugin. */ -export interface KanbanColumn { +export interface DeclarativeKanbanColumn { /** * Unique column identifier */ @@ -45,7 +66,7 @@ export interface KanbanColumn { * spelling with zero read sites, which made every authored board fail * `safeValidateSchema` while rendering correctly (objectui#6318's bucket). */ - cards: KanbanCard[]; + cards: DeclarativeKanbanCard[]; /** * Column color/variant */ @@ -63,7 +84,7 @@ export interface KanbanColumn { /** * Kanban card */ -export interface KanbanCard { +export interface DeclarativeKanbanCard { /** * Unique card identifier */ @@ -105,12 +126,12 @@ export interface KanbanCard { /** * Kanban board component */ -export interface KanbanSchema extends BaseSchema { +export interface DeclarativeKanbanSchema extends BaseSchema { type: 'kanban'; /** * Kanban columns */ - columns: KanbanColumn[]; + columns: DeclarativeKanbanColumn[]; /** * Enable drag and drop * @default true @@ -133,7 +154,7 @@ export interface KanbanSchema extends BaseSchema { * name and points at the node-type spelling. Kept callable here because it is * forwarded by `plugin-kanban` (`onCardClick={schema.onCardClick}`). */ - onCardClick?: (card: KanbanCard) => void; + onCardClick?: (card: DeclarativeKanbanCard) => void; /** * RETIRED (objectui#6124, ADR-0049) — JSON has no function value, and the * `kanban` renderer takes `({ schema })` and never reads it. The zod twin @@ -1188,7 +1209,7 @@ export interface DashboardComponentSchema extends BaseSchema { * Union type of all complex schemas */ export type ComplexSchema = - | KanbanSchema + | DeclarativeKanbanSchema | CalendarViewSchema | FilterBuilderSchema | CarouselSchema diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index cd3134a9a6..1216ff51ca 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -289,9 +289,9 @@ export type { // Complex Components - Advanced/Composite Components // ============================================================================ export type { - KanbanColumn, - KanbanCard, - KanbanSchema, + DeclarativeKanbanColumn, + DeclarativeKanbanCard, + DeclarativeKanbanSchema, CalendarViewMode, CalendarEvent, CalendarViewSchema, diff --git a/packages/types/src/registry.ts b/packages/types/src/registry.ts index d354e0281c..11c9034f4b 100644 --- a/packages/types/src/registry.ts +++ b/packages/types/src/registry.ts @@ -92,7 +92,7 @@ import type { } from './navigation.js'; import type { - KanbanSchema, + DeclarativeKanbanSchema, CalendarViewSchema, FilterBuilderSchema, CarouselSchema, @@ -183,7 +183,14 @@ export interface SchemaRegistry { 'pagination': PaginationSchema; // Complex - 'kanban': KanbanSchema; + // ⚠️ The renderer registered for `'kanban'` (`ObjectKanbanRenderer`, in + // `@object-ui/plugin-kanban`) consumes that package's own `KanbanSchema`, + // NOT this declarative face. The mismatch is latent — the value side of this + // map is reached only through `ComponentType = keyof SchemaRegistry` and + // nothing performs an indexed access — and objectui#6172's ruling (option A) + // renamed the declarative copy rather than relocating the plugin dialect + // into this zero-dependency layer, so the mismatch stays latent-but-named. + 'kanban': DeclarativeKanbanSchema; 'calendar-view': CalendarViewSchema; 'filter-builder': FilterBuilderSchema; 'carousel': CarouselSchema; diff --git a/packages/types/src/zod/README.md b/packages/types/src/zod/README.md index 8ed83afc41..28916d4964 100644 --- a/packages/types/src/zod/README.md +++ b/packages/types/src/zod/README.md @@ -210,7 +210,7 @@ function validateComponent(config: unknown) { - `PaginationSchema`, `NavigationMenuSchema`, `ButtonGroupSchema` ### Complex Components (5) -- `KanbanSchema`, `CalendarViewSchema` +- `DeclarativeKanbanSchema`, `CalendarViewSchema` - `FilterBuilderSchema`, `CarouselSchema`, `ChatbotSchema` ## Schema Structure diff --git a/packages/types/src/zod/complex.zod.ts b/packages/types/src/zod/complex.zod.ts index b0503d08e4..ee25b16a1d 100644 --- a/packages/types/src/zod/complex.zod.ts +++ b/packages/types/src/zod/complex.zod.ts @@ -34,7 +34,7 @@ import { /** * Kanban Card Schema */ -export const KanbanCardSchema = z.object({ +export const DeclarativeKanbanCardSchema = z.object({ id: z.string().describe('Card ID'), title: z.string().describe('Card title'), description: z.string().optional().describe('Card description'), @@ -49,10 +49,10 @@ export const KanbanCardSchema = z.object({ /** * Kanban Column Schema */ -export const KanbanColumnSchema = z.object({ +export const DeclarativeKanbanColumnSchema = z.object({ id: z.string().describe('Column ID'), title: z.string().describe('Column title'), - cards: z.array(KanbanCardSchema).describe('Column cards'), + cards: z.array(DeclarativeKanbanCardSchema).describe('Column cards'), color: z.string().optional().describe('Column color'), limit: z.number().optional().describe('Card limit'), collapsed: z.boolean().optional().describe('Whether column is collapsed'), @@ -61,9 +61,9 @@ export const KanbanColumnSchema = z.object({ /** * Kanban Schema - Kanban board component */ -export const KanbanSchema = BaseSchema.extend({ +export const DeclarativeKanbanSchema = BaseSchema.extend({ type: z.literal('kanban'), - columns: z.array(KanbanColumnSchema).describe('Kanban columns'), + columns: z.array(DeclarativeKanbanColumnSchema).describe('Kanban columns'), draggable: z.boolean().optional().describe('Whether cards are draggable'), onCardMove: handlerKeyRefusal('onCardMove', 'runtime-slot', 'Card move handler'), onCardClick: handlerKeyRefusal('onCardClick', 'runtime-slot', 'Card click handler'), @@ -766,7 +766,7 @@ export const DashboardConfigSchema = z.object({ * Complex Schema Union - All complex component schemas */ export const ComplexSchema = z.discriminatedUnion('type', [ - KanbanSchema, + DeclarativeKanbanSchema, CalendarViewSchema, FilterBuilderSchema, CarouselSchema, diff --git a/packages/types/src/zod/index.zod.ts b/packages/types/src/zod/index.zod.ts index 945e9a7b8a..cba8d1aa1a 100644 --- a/packages/types/src/zod/index.zod.ts +++ b/packages/types/src/zod/index.zod.ts @@ -217,9 +217,9 @@ export { // Complex Components - Advanced/Composite Components // ============================================================================ export { - KanbanCardSchema, - KanbanColumnSchema, - KanbanSchema, + DeclarativeKanbanCardSchema, + DeclarativeKanbanColumnSchema, + DeclarativeKanbanSchema, CalendarViewModeSchema, CalendarEventSchema, CalendarViewSchema, diff --git a/scripts/__tests__/one-authority-per-exported-name-6273.test.ts b/scripts/__tests__/one-authority-per-exported-name-6273.test.ts index e9959e3092..906488fbea 100644 --- a/scripts/__tests__/one-authority-per-exported-name-6273.test.ts +++ b/scripts/__tests__/one-authority-per-exported-name-6273.test.ts @@ -394,20 +394,21 @@ const KNOWN_COLLISIONS: ReadonlyMap = new Map([ // authority left the tree with the spec-bridge retirement (objectui#6366, // 2026-08-27 maintainer ruling), so app-shell's `form-spec.ts` is now the // one authority and the entries would fail the stale-baseline direction. - // `KanbanCard` / `KanbanColumn` were the ×4 objectui#6155 measured. The THREE - // in-package copies converged (objectui#6172): `KanbanImpl.tsx` and - // `KanbanEnhanced.tsx` were strict-SUBSET copies of `./types` — an AST probe - // found nothing typed differently between them — so their members (`coverImage`, - // `cardSubtitle`, `cardFieldCells`, `collapsed`, all optional) moved onto the one - // in-package declaration and both files now re-point at it. Two sites remain, and - // they are the CROSS-package pair: the `@object-ui/types` copy is a different - // dialect (`items` where the plugin says `cards`, `labels` where it says - // `badges`), so collapsing it is a rename of a published name and needs an - // authority ruling the 2026-08-25 family ruling did not give for this pair — it - // named one only for the cross-package `FormField` clash. Escalated, not guessed. - ['KanbanCard', ['packages/plugin-kanban/src/types.ts', 'packages/types/src/complex.ts']], - ['KanbanColumn', ['packages/plugin-kanban/src/types.ts', 'packages/types/src/complex.ts']], - ['KanbanSchema', ['packages/plugin-kanban/src/types.ts', 'packages/types/src/complex.ts']], // objectui#6172 — same cross-package pair, same escalation + // `KanbanCard` / `KanbanColumn` / `KanbanSchema` sat here. They were the ×4 + // objectui#6155 measured; objectui#6172 converged the THREE in-package copies + // (`KanbanImpl.tsx` and `KanbanEnhanced.tsx` were strict-SUBSET copies of + // `./types` — an AST probe found nothing typed differently — so their members + // moved onto the one in-package declaration and both files re-point at it), + // leaving the CROSS-package pair. That pair needed an authority ruling the + // 2026-08-25 family ruling gave only for `FormField`, and the 2026-08-31 + // maintainer ruling (决裁批 #14, option A) gave it: `@object-ui/plugin-kanban` + // KEEPS the bare names — the dialect all four registered renderers consume — + // and the `@object-ui/types` trio is renamed `DeclarativeKanbanSchema` / + // `DeclarativeKanbanColumn` / `DeclarativeKanbanCard`. The deciding axis: the + // surviving bare name must be the one a renderer honours, because + // objectui#6086 measured that auto-importing the wrong copy yields a confident + // EMPTY BOARD rather than an abstention. One authority each now, so all three + // entries would fail the stale-baseline direction. // `MarkdownSchema` sat here, colliding between // `packages/plugin-markdown/src/types.ts` and `packages/types/src/data-display.ts`. // The copies differed on ONE member — `content`, required there and optional here —