From 41ff58ff7e5e4d87d986b05dc6863c5fcfc23a0b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 15:53:06 +0000 Subject: [PATCH 1/3] fix(types): SchemaRegistry's kanban entry stops describing a component it cannot name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `SchemaRegistry` advertises itself as the Single Source of Truth for component type lookups, but its `'kanban'` entry named `DeclarativeKanbanSchema` — this package's authoring/validation face — while the renderer registered for that key is `ObjectKanbanRenderer` in `@object-ui/plugin-kanban`, which consumes that package's own `KanbanSchema`. Unrelated dialects, so for this one key the map's value did not describe the component the key names (objectui#7645). Correcting the value is not reachable from this layer, measured rather than assumed: importing the plugin is a phantom dependency (`check:phantom-deps` rejects the pair, type-only included), and declaring the dependency closes the cycle `@object-ui/types` -> `@object-ui/plugin-kanban` -> `@object-ui/types`. objectui#6172's ruling kept the plugin's bare names rather than relocating the dialect into this zero-workspace-dependency layer, so the gap is by decision. The entry therefore asserts only what this layer can prove and what both dialects satisfy: `BaseSchema & { type: 'kanban' }`. `keyof SchemaRegistry` is unchanged — removing the key would silently narrow the published `ComponentType` union — and two compile-time pins hold that shape: one here (the key survives; the value no longer claims the declarative face) and one in `@object-ui/plugin-kanban`, the only package that can name both sides, proving the renderer's own `KanbanSchema` satisfies what the entry now asserts. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3 --- .../7645-schema-registry-kanban-honesty.md | 37 ++++++++ ...chema-registry-kanban-honesty-7645.test.ts | 84 +++++++++++++++++ ...chema-registry-kanban-honesty-7645.test.ts | 94 +++++++++++++++++++ packages/types/src/registry.ts | 43 +++++++-- 4 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 .changeset/7645-schema-registry-kanban-honesty.md create mode 100644 packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts create mode 100644 packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts diff --git a/.changeset/7645-schema-registry-kanban-honesty.md b/.changeset/7645-schema-registry-kanban-honesty.md new file mode 100644 index 0000000000..f240679643 --- /dev/null +++ b/.changeset/7645-schema-registry-kanban-honesty.md @@ -0,0 +1,37 @@ +--- +'@object-ui/types': minor +--- + +`SchemaRegistry['kanban']` stops describing a component it cannot name + +`SchemaRegistry` documents itself as "the Single Source of Truth for component +type lookups". Its `'kanban'` entry named `DeclarativeKanbanSchema` — the +authoring/validation face declared in this package — while the renderer +registered for that key is `ObjectKanbanRenderer` in `@object-ui/plugin-kanban` +(`ComponentRegistry.register('kanban', …)`), which consumes that package's own +`KanbanSchema`. The two are structurally unrelated dialects: 19 members against +the declarative face's own set, sharing only the `type` tag. For this one key +the map's value did not describe the component the key names. + +Pointing the entry at the honest type is not reachable from this layer, and +that was measured rather than assumed. Importing `@object-ui/plugin-kanban` +here is a phantom dependency — `check:phantom-deps` rejects it by file and +pair, type-only imports included — and declaring the dependency would close the +cycle `@object-ui/types` → `@object-ui/plugin-kanban` → `@object-ui/types`, +because this package is the zero-workspace-dependency bottom layer. +objectui#6172's ruling kept the plugin's bare names rather than relocating that +dialect down here, so the gap is permanent by decision. + +So the entry now asserts only what this layer can prove, and what BOTH dialects +satisfy: `BaseSchema & { type: 'kanban' }`. + +**What this changes for consumers.** `keyof SchemaRegistry` — and therefore the +published `ComponentType` union — is unchanged; `'kanban'` is still a member, +pinned at compile time so it cannot be narrowed away silently. What changes is +the value side of this one key: `SchemaRegistry['kanban']` no longer resolves to +`DeclarativeKanbanSchema`. Code that read members off it gets the base node +shape instead and should name the face it actually means — +`DeclarativeKanbanSchema` is still exported from `@object-ui/types` unchanged +for the authoring face, and `KanbanSchema` from `@object-ui/plugin-kanban` for +the rendered one. Nothing in this repository performed such an indexed access, +which is why this is a correction rather than a break. diff --git a/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts b/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts new file mode 100644 index 0000000000..b4934b7595 --- /dev/null +++ b/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts @@ -0,0 +1,84 @@ +/** + * 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. + */ + +/** + * The renderer's own face satisfies what `SchemaRegistry['kanban']` asserts. + * + * ## Why this pin lives here and can live nowhere else + * + * objectui#7645: `@object-ui/types`' `SchemaRegistry` advertises itself as the + * Single Source of Truth for component type lookups, and its `'kanban'` entry + * named the DECLARATIVE authoring face while the renderer registered for that + * key — `ObjectKanbanRenderer`, `ComponentRegistry.register('kanban', …)` in + * `../index` — consumes {@link KanbanSchema} from this package. The two are + * unrelated dialects (objectui#6172 ruled this package KEEPS the bare names). + * + * The entry was therefore weakened to the claim that layer can prove and both + * dialects satisfy: a schema node tagged `'kanban'`. That claim is only worth + * anything if it is actually TRUE of the renderer's face — and + * `@object-ui/types` cannot check that, because it cannot name this package: + * the import is a phantom dependency and declaring it would close the cycle + * `@object-ui/types` → `@object-ui/plugin-kanban` → `@object-ui/types`. This + * package depends on `@object-ui/types`, so it is the only place in the + * workspace that can see both sides at once. That is the whole reason this + * file exists rather than one more pin next to the map. + * + * ⛔ This file does not touch {@link KanbanSchema} — it only reads it. The + * plugin dialect is the face objectui#6172 ruled kept, and `KanbanSchema.data` + * is objectui#7651, an open maintainer decision. + * + * ## The instrument + * + * Compile-time only. Vitest strips types without checking them, so a green run + * of this file proves nothing on its own; the assertions are read by + * `tsc -p packages/plugin-kanban/tsconfig.test.json`, chained off this + * package's `type-check` script. That project sets `"paths": {}`, so + * `@object-ui/types` resolves through the workspace dependency to + * `packages/types/dist/index.d.ts` — BUILD `@object-ui/types` before believing + * either colour this file reports. + */ + +import { describe, it, expect } from 'vitest'; +import type { SchemaRegistry, DeclarativeKanbanSchema } from '@object-ui/types'; +import type { KanbanSchema } from '../types'; + +/* -------------------------------------------------------------------------- */ +/* Compile-time pins — compiled by tsconfig.test.json, chained off type-check. */ +/* -------------------------------------------------------------------------- */ + +type Assert = T; +type Equal = (() => T extends A ? 1 : 2) extends () => T extends B ? 1 : 2 ? true : false; +type IsAny = 0 extends 1 & T ? true : false; + +describe("the registered kanban renderer's schema satisfies the registry entry", () => { + it('is pinned at compile time', () => { + // Non-vacuity controls: `any` on either side would satisfy every `extends` + // below while checking nothing. + type _PluginFaceIsReal = Assert, false>>; + type _RegistryIsReal = Assert, false>>; + + // 1. The claim the map now makes for `'kanban'` is TRUE of the face the + // registered renderer actually consumes. This is the assertion that + // makes the weakened entry honest rather than merely vaguer. + type _PluginFaceSatisfiesTheEntry = Assert< + KanbanSchema extends SchemaRegistry['kanban'] ? true : false + >; + + // 2. …and it is still two dialects, not one. If these ever converge, the + // weakened entry has outlived its reason and objectui#7645 should be + // re-triaged rather than left as a permanent retreat. + type _StillTwoDialects = Assert< + Equal, false> + >; + + // 3. Both faces agree on the one thing the map asserts: the tag. + type _PluginFaceIsTagged = Assert>; + + expect(true).toBe(true); + }); +}); diff --git a/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts b/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts new file mode 100644 index 0000000000..2859fd626f --- /dev/null +++ b/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts @@ -0,0 +1,94 @@ +/** + * 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. + */ + +/** + * `SchemaRegistry['kanban']` — the key survives, the value stops asserting. + * + * ## What this pins, and why the key half is the load-bearing half + * + * `ComponentType = keyof SchemaRegistry` is a PUBLISHED union. The remedy for + * objectui#7645 (this map's `'kanban'` value described the declarative + * authoring face, not the type the registered renderer honours) had to leave + * that union byte-identical: dropping the key would silently narrow a + * published type, turning a false claim into a missing one. So the value was + * weakened to what this layer can prove and the KEY was kept — and only a pin + * can tell those two edits apart afterwards, because deleting the entry + * outright also removes the false claim and every runtime suite stays green. + * + * ## Why the value cannot simply be corrected + * + * The renderer registered for `'kanban'` is `ObjectKanbanRenderer` in + * `@object-ui/plugin-kanban`, which consumes that package's `KanbanSchema`. + * `@object-ui/types` cannot name it: the import is a phantom dependency + * (`check:phantom-deps` names the pair), and declaring the dependency closes + * the cycle `@object-ui/types` → `@object-ui/plugin-kanban` → + * `@object-ui/types`. objectui#6172's ruling kept the plugin's bare names + * rather than relocating that dialect into this zero-dependency layer, so the + * gap is permanent by decision. The half of the claim that IS provable here — + * a schema node tagged `'kanban'` — is what the entry now states, and the + * plugin side proves its own face satisfies it in + * `packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts`. + * + * ## These assertions are compile-time only + * + * They mean something only because this package type-checks its tests: + * `tsconfig.json` excludes test files (they must not emit into `dist`) and + * `tsconfig.test.json` picks them back up, chained off the package's + * `type-check` script. Vitest strips types without checking them, so a green + * vitest run is NOT evidence about anything below. The instrument is + * `tsc -p packages/types/tsconfig.test.json`. + */ + +import { describe, it, expect } from 'vitest'; +import type { + SchemaRegistry, + ComponentType, + DeclarativeKanbanSchema, +} from '../index'; + +/* -------------------------------------------------------------------------- */ +/* Compile-time pins — compiled by tsconfig.test.json, chained off type-check. */ +/* -------------------------------------------------------------------------- */ + +type Assert = T; +type Equal = (() => T extends A ? 1 : 2) extends () => T extends B ? 1 : 2 ? true : false; +type IsAny = 0 extends 1 & T ? true : false; + +describe("SchemaRegistry's kanban key outlives its value's retreat", () => { + it('is pinned at compile time', () => { + // Non-vacuity controls. `Equal` is `false` and `any` satisfies + // every `extends`, so an `any` on either side would let the pins below + // pass while checking nothing at all. + type _RegistryIsReal = Assert, false>>; + type _DeclarativeIsReal = Assert, false>>; + + // 1. The published union still yields `'kanban'`. `Extract` collapses to + // `never` if the key is ever removed, which fails this pin loudly. + type _KeyKept = Assert, 'kanban'>>; + + // 2. The value no longer claims the declarative authoring face. This is + // the objectui#7645 defect itself; re-pointing the entry turns it red. + type _ValueIsNotTheDeclarativeFace = Assert< + Equal, false> + >; + + // 3. What it DOES assert is true and non-empty: a node tagged `'kanban'`. + // `never` or `unknown` in that slot fails here rather than passing as a + // quieter kind of nothing. + type _ValueIsATaggedNode = Assert>; + + // 4. Nothing was invalidated by the retreat: the declarative face still + // satisfies the weaker claim, as does the plugin's face (pinned in + // `@object-ui/plugin-kanban`, the only package that can name both). + type _DeclarativeStillSatisfiesIt = Assert< + DeclarativeKanbanSchema extends SchemaRegistry['kanban'] ? true : false + >; + + expect(true).toBe(true); + }); +}); diff --git a/packages/types/src/registry.ts b/packages/types/src/registry.ts index 11c9034f4b..c6e89c27b0 100644 --- a/packages/types/src/registry.ts +++ b/packages/types/src/registry.ts @@ -6,6 +6,8 @@ * LICENSE file in the root directory of this source tree. */ +import type { BaseSchema } from './base.js'; + import type { DivSchema, BoxSchema, @@ -92,7 +94,6 @@ import type { } from './navigation.js'; import type { - DeclarativeKanbanSchema, CalendarViewSchema, FilterBuilderSchema, CarouselSchema, @@ -183,14 +184,38 @@ export interface SchemaRegistry { 'pagination': PaginationSchema; // Complex - // ⚠️ 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; + // ⚠️ `'kanban'` is the one key whose value this layer cannot state + // precisely, so it deliberately states LESS rather than stating it wrongly + // (objectui#7645). + // + // The renderer registered for this key is `ObjectKanbanRenderer` in + // `@object-ui/plugin-kanban` (`ComponentRegistry.register('kanban', …)`, + // `plugin-kanban/src/index.tsx`), and it consumes THAT package's + // `KanbanSchema`. `@object-ui/types` cannot name that type, measured two + // ways: importing it is a phantom dependency this package does not declare + // (`check:phantom-deps` rejects it by file and pair), and declaring the + // dependency would close the cycle `@object-ui/types` → + // `@object-ui/plugin-kanban` → `@object-ui/types` — this is the + // zero-workspace-dependency bottom layer. objectui#6172's ruling (option A) + // kept the plugin's bare names rather than relocating that dialect down + // here, so the gap is permanent by decision, not by oversight. + // + // What this entry asserts is therefore only what this layer can PROVE, and + // what BOTH dialects satisfy: a schema node tagged `'kanban'`. It no longer + // names `DeclarativeKanbanSchema` — that is the AUTHORING/validation face + // (the `'kanban'` arm of `ComplexSchema` → `AnyComponentSchema` → + // `safeValidateSchema`, still exported from `./complex.js` and unchanged), + // not the type the registered renderer honours. Naming it here made a map + // that advertises itself as the Single Source of Truth describe a different + // component than the key names. + // + // ⛔ Do not "restore" a precise type here without moving the renderer's + // dialect into a layer this package may depend on. Two compile-time pins + // hold the shape: `src/__tests__/schema-registry-kanban-honesty-7645.test.ts` + // (the key survives in `keyof`; the value no longer claims the declarative + // face) and the same file name under `plugin-kanban/src/__tests__/` (the + // renderer's own `KanbanSchema` satisfies what this entry asserts). + 'kanban': BaseSchema & { type: 'kanban' }; 'calendar-view': CalendarViewSchema; 'filter-builder': FilterBuilderSchema; 'carousel': CarouselSchema; From 3748de9af8019c230f35c6c66509d2ab4c73c1f6 Mon Sep 17 00:00:00 2001 From: os-sam Date: Sat, 5 Sep 2026 02:18:01 +0000 Subject: [PATCH 2/3] docs(changeset): name the SchemaRegistry['kanban'] break and the silent any-read Contract review (PR #7662) refused the changeset alone: the code and pins were judged sound and `minor` correct, but the release-note input claimed the two kanban dialects share "only the type tag" (measured: 3 shared names of 7 vs 19 body members - type, columns, onCardMove), called a measured compile break "a correction rather than a break", and omitted that BaseSchema's index signature turns the declarative members' reads into silent any. Re-measured on the merge-base and head trees with lit controls before this rewrite: SchemaRegistry['kanban'] -> DeclarativeKanbanSchema compiles at base and is TS2741 at head; SchemaRegistry['kanban']['columns'] is DeclarativeKanbanColumn[] at base and any at head. The changeset now states both effects and keeps the bump at minor per the version-alignment rule. No source or test file changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3 --- .../7645-schema-registry-kanban-honesty.md | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/.changeset/7645-schema-registry-kanban-honesty.md b/.changeset/7645-schema-registry-kanban-honesty.md index f240679643..7ef783c570 100644 --- a/.changeset/7645-schema-registry-kanban-honesty.md +++ b/.changeset/7645-schema-registry-kanban-honesty.md @@ -9,9 +9,15 @@ type lookups". Its `'kanban'` entry named `DeclarativeKanbanSchema` — the authoring/validation face declared in this package — while the renderer registered for that key is `ObjectKanbanRenderer` in `@object-ui/plugin-kanban` (`ComponentRegistry.register('kanban', …)`), which consumes that package's own -`KanbanSchema`. The two are structurally unrelated dialects: 19 members against -the declarative face's own set, sharing only the `type` tag. For this one key -the map's value did not describe the component the key names. +`KanbanSchema`. The two are distinct dialects, measured member by member: the +plugin face declares 19 members in its own body, the declarative face 7, and +they share three names — `type`, `columns` and `onCardMove`. `onCardMove` has +the same signature on both sides; `columns` is required +`DeclarativeKanbanColumn[]` on one and optional `KanbanColumn[]` on the other, +the two element types sharing five of their six members; the remaining 16 +plugin members and the declarative `draggable` / `onCardClick` have no +counterpart across the gap. For this one key the map's value did not describe +the component the key names. Pointing the entry at the honest type is not reachable from this layer, and that was measured rather than assumed. Importing `@object-ui/plugin-kanban` @@ -28,10 +34,30 @@ satisfy: `BaseSchema & { type: 'kanban' }`. **What this changes for consumers.** `keyof SchemaRegistry` — and therefore the published `ComponentType` union — is unchanged; `'kanban'` is still a member, pinned at compile time so it cannot be narrowed away silently. What changes is -the value side of this one key: `SchemaRegistry['kanban']` no longer resolves to -`DeclarativeKanbanSchema`. Code that read members off it gets the base node -shape instead and should name the face it actually means — -`DeclarativeKanbanSchema` is still exported from `@object-ui/types` unchanged -for the authoring face, and `KanbanSchema` from `@object-ui/plugin-kanban` for -the rendered one. Nothing in this repository performed such an indexed access, -which is why this is a correction rather than a break. +the value side of this one key, in two ways, one loud and one silent: + +- **Breaking, loudly, for consumers who indexed `SchemaRegistry['kanban']` and + flowed the value into the declarative face.** Before this change + `SchemaRegistry['kanban']` *was* `DeclarativeKanbanSchema`, so + `const s: DeclarativeKanbanSchema = registryValue` compiled. It no longer + does: the entry lacks the required `columns` member, and that assignment is + a compile error (TS2741). Nothing in this repository performed such an + indexed access, so no in-repo code moves — the break is for consumers + outside it. +- **Silent, for member reads.** `BaseSchema` carries an index signature + (`[key: string]: any`), so reading the declarative face's own members — + `columns`, `draggable`, `onCardMove`, `onCardClick` — off the new entry is + not an error: the reads resolve through the index signature and type as + `any`. `SchemaRegistry['kanban']['columns']` was `DeclarativeKanbanColumn[]` + and is now `any`; nothing turns red, the read just stops being checked. + (Undeclared keys already read as `any` before, through the same signature; + what changes is those declared members.) + +Migration: name the face you actually mean. `DeclarativeKanbanSchema` is still +exported from `@object-ui/types` unchanged for the authoring face, and +`KanbanSchema` from `@object-ui/plugin-kanban` for the rendered one. + +This is a breaking change shipped as `minor`: this repository's +version-alignment rule keeps objectui's major pinned to `@objectstack`'s and +ships objectui's own breaking changes as `minor` with the break spelled out in +the changeset body, which is what the two bullets above are. From 55a7470e9b413fd5ced9439809d0be874971e06b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 02:53:54 +0000 Subject: [PATCH 3/3] docs(types): the kanban registry gap is transitional under objectui#7664 (a), not permanent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wording only. The changeset, the comment above SchemaRegistry['kanban'] in registry.ts, and both pin docblocks said the types-vs-plugin kanban gap was "permanent by decision". objectui#6172's ruling (2026-08-31) kept the plugin's bare names; objectui#7664's ruling (a) (2026-09-05T02:09:40Z) reverses that half — the @object-ui/types 'kanban' arm is rewritten to the plugin's shape, plugin-kanban conforms to it, the DeclarativeKanban* trio retires, and registry.ts is on its execution list — so this PR's BaseSchema & { type: 'kanban' } entry is the transitional state under that ruling. The plugin pin also called objectui#7651 "an open maintainer decision"; it was ruled B and closed not_planned at 2026-09-05T02:09:54Z. No executable line moves: the TypeScript token stream (trivia dropped) of all three .ts files is identical before and after, the type line registry.ts:218 is byte-identical, and every file keeps its line count so the pins' cited lines stay put. Both pins read exit 0 through their declared instruments (tsc -p packages/types/tsconfig.test.json, tsc -p packages/plugin-kanban/tsconfig.test.json against the rebuilt dist). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3 --- .../7645-schema-registry-kanban-honesty.md | 10 +++++-- ...chema-registry-kanban-honesty-7645.test.ts | 26 +++++++++---------- ...chema-registry-kanban-honesty-7645.test.ts | 12 ++++----- packages/types/src/registry.ts | 20 +++++++------- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/.changeset/7645-schema-registry-kanban-honesty.md b/.changeset/7645-schema-registry-kanban-honesty.md index 7ef783c570..8322a99834 100644 --- a/.changeset/7645-schema-registry-kanban-honesty.md +++ b/.changeset/7645-schema-registry-kanban-honesty.md @@ -25,8 +25,14 @@ here is a phantom dependency — `check:phantom-deps` rejects it by file and pair, type-only imports included — and declaring the dependency would close the cycle `@object-ui/types` → `@object-ui/plugin-kanban` → `@object-ui/types`, because this package is the zero-workspace-dependency bottom layer. -objectui#6172's ruling kept the plugin's bare names rather than relocating that -dialect down here, so the gap is permanent by decision. +objectui#6172's ruling (2026-08-31) kept the plugin's bare names rather than +relocating that dialect down here — that is why this entry cannot name the +plugin's type at this commit. That half of the ruling has since been reversed: +objectui#7664's ruling (a) (2026-09-05) rewrites this package's `'kanban'` +arm to the plugin's shape, has `@object-ui/plugin-kanban` conform to it, and +retires the `DeclarativeKanban*` trio; `registry.ts` is on its execution list, +so this entry is scheduled to be re-pointed at the declared type. The value +below is the transitional state under that ruling, not the permanent one. So the entry now asserts only what this layer can prove, and what BOTH dialects satisfy: `BaseSchema & { type: 'kanban' }`. diff --git a/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts b/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts index b4934b7595..27b0874579 100644 --- a/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts +++ b/packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts @@ -20,17 +20,17 @@ * * The entry was therefore weakened to the claim that layer can prove and both * dialects satisfy: a schema node tagged `'kanban'`. That claim is only worth - * anything if it is actually TRUE of the renderer's face — and - * `@object-ui/types` cannot check that, because it cannot name this package: - * the import is a phantom dependency and declaring it would close the cycle - * `@object-ui/types` → `@object-ui/plugin-kanban` → `@object-ui/types`. This - * package depends on `@object-ui/types`, so it is the only place in the - * workspace that can see both sides at once. That is the whole reason this - * file exists rather than one more pin next to the map. + * anything if it is actually TRUE of the renderer's face — and `@object-ui/types` + * cannot check that: it cannot name this package (the import is a phantom + * dependency; declaring it would close the cycle `@object-ui/types` → + * `@object-ui/plugin-kanban` → `@object-ui/types`). This package depends on + * `@object-ui/types`, so it is the only place in the workspace that can see both + * sides at once — which is why this file exists, not one more pin by the map. * - * ⛔ This file does not touch {@link KanbanSchema} — it only reads it. The - * plugin dialect is the face objectui#6172 ruled kept, and `KanbanSchema.data` - * is objectui#7651, an open maintainer decision. + * ⛔ This file does not touch {@link KanbanSchema} — it only reads it. It is the + * face objectui#6172 kept, and the one objectui#7664's ruling (a) (2026-09-05) + * makes the declared shape; `KanbanSchema.data` stays a raw-row input, since + * objectui#7651 was ruled B and closed as not_planned (2026-09-05T02:09:54Z). * * ## The instrument * @@ -69,9 +69,9 @@ describe("the registered kanban renderer's schema satisfies the registry entry", KanbanSchema extends SchemaRegistry['kanban'] ? true : false >; - // 2. …and it is still two dialects, not one. If these ever converge, the - // weakened entry has outlived its reason and objectui#7645 should be - // re-triaged rather than left as a permanent retreat. + // 2. …and, at this commit, still two dialects. objectui#7664's ruling (a) + // (2026-09-05) schedules their convergence; when it lands, the weakened + // entry has outlived its reason and this pin retires with the re-point. type _StillTwoDialects = Assert< Equal, false> >; diff --git a/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts b/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts index 2859fd626f..f8a094d4ba 100644 --- a/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts +++ b/packages/types/src/__tests__/schema-registry-kanban-honesty-7645.test.ts @@ -26,12 +26,12 @@ * `@object-ui/plugin-kanban`, which consumes that package's `KanbanSchema`. * `@object-ui/types` cannot name it: the import is a phantom dependency * (`check:phantom-deps` names the pair), and declaring the dependency closes - * the cycle `@object-ui/types` → `@object-ui/plugin-kanban` → - * `@object-ui/types`. objectui#6172's ruling kept the plugin's bare names - * rather than relocating that dialect into this zero-dependency layer, so the - * gap is permanent by decision. The half of the claim that IS provable here — - * a schema node tagged `'kanban'` — is what the entry now states, and the - * plugin side proves its own face satisfies it in + * the cycle `@object-ui/types` → `@object-ui/plugin-kanban` → `@object-ui/types`. + * objectui#6172's ruling (2026-08-31) kept the plugin's bare names there; + * objectui#7664's ruling (a) (2026-09-05) reverses that half — this package's + * `'kanban'` arm is rewritten to the plugin's shape and the entry re-pointed at + * it, so the value pinned below is TRANSITIONAL. What IS provable here — a + * node tagged `'kanban'` — is what it states; the plugin's face satisfies it in * `packages/plugin-kanban/src/__tests__/schema-registry-kanban-honesty-7645.test.ts`. * * ## These assertions are compile-time only diff --git a/packages/types/src/registry.ts b/packages/types/src/registry.ts index c6e89c27b0..b4b0b62abc 100644 --- a/packages/types/src/registry.ts +++ b/packages/types/src/registry.ts @@ -196,18 +196,18 @@ export interface SchemaRegistry { // (`check:phantom-deps` rejects it by file and pair), and declaring the // dependency would close the cycle `@object-ui/types` → // `@object-ui/plugin-kanban` → `@object-ui/types` — this is the - // zero-workspace-dependency bottom layer. objectui#6172's ruling (option A) - // kept the plugin's bare names rather than relocating that dialect down - // here, so the gap is permanent by decision, not by oversight. + // zero-workspace-dependency bottom layer. objectui#6172's ruling (option A, + // 2026-08-31) kept the plugin's bare names rather than relocating that + // dialect down here. objectui#7664's ruling (a) (2026-09-05) reverses that + // half: this package's `'kanban'` arm is rewritten to the plugin's shape and + // this entry is re-pointed at the declared type — this value is TRANSITIONAL. // - // What this entry asserts is therefore only what this layer can PROVE, and - // what BOTH dialects satisfy: a schema node tagged `'kanban'`. It no longer - // names `DeclarativeKanbanSchema` — that is the AUTHORING/validation face - // (the `'kanban'` arm of `ComplexSchema` → `AnyComponentSchema` → - // `safeValidateSchema`, still exported from `./complex.js` and unchanged), + // Until then the entry asserts only what this layer can PROVE, and what BOTH + // dialects satisfy: a schema node tagged `'kanban'`. It no longer names + // `DeclarativeKanbanSchema` — the AUTHORING/validation face (the `'kanban'` + // arm of `ComplexSchema` → `AnyComponentSchema` → `safeValidateSchema`), // not the type the registered renderer honours. Naming it here made a map - // that advertises itself as the Single Source of Truth describe a different - // component than the key names. + // that calls itself the Single Source of Truth describe the wrong component. // // ⛔ Do not "restore" a precise type here without moving the renderer's // dialect into a layer this package may depend on. Two compile-time pins