diff --git a/.changeset/theme-zod-retired-spec-reexports.md b/.changeset/theme-zod-retired-spec-reexports.md new file mode 100644 index 000000000..68023be60 --- /dev/null +++ b/.changeset/theme-zod-retired-spec-reexports.md @@ -0,0 +1,7 @@ +--- +'@object-ui/types': minor +--- + +Remove the six retired `@objectstack/spec/ui` theme-schema re-exports from `@object-ui/types/zod` — `ColorPaletteSchema`, `TypographySchema`, `BorderRadiusSchema`, `ShadowSchema`, `ThemeModeSchema`, `ThemeDefinitionSchema` (the spec's `ThemeSchema`) — plus their `…SchemaType` inference helpers, and the `theme` / `mode` props of `ThemePreviewSchema` (zod and interface) that consumed them. + +objectstack#10485 (ADR-0049 enforce-or-remove, PR objectstack#10695) retired the spec's whole `ui/theme.zod.ts` module, and the maintainer's ruling on objectstack#10856 (Options A + C) has objectui remove the dangling imports first so the Console Pin Gate can build objectui against the framework tree; restoring the spec exports (Option B) was explicitly not taken. Breaking in effect for anyone importing those six names from `@object-ui/types/zod`: there is no replacement — the validators retired upstream with no successor. The theme TYPE surface (`Theme`, `ThemeMode`, `ColorPalette`, … re-exported from `@object-ui/types`) and the ThemeEngine/ThemeProvider runtime are unchanged. diff --git a/packages/types/src/__tests__/p2-spec-exports.test.ts b/packages/types/src/__tests__/p2-spec-exports.test.ts index cb2724f27..fc49cff22 100644 --- a/packages/types/src/__tests__/p2-spec-exports.test.ts +++ b/packages/types/src/__tests__/p2-spec-exports.test.ts @@ -67,8 +67,11 @@ import { UserActionsConfigSchema as UserActionsConfigZod, ViewTabSchema as ViewTabZod, ViewFilterRuleSchema as ViewFilterRuleZod, - ThemeModeSchema as ThemeModeZod, } from '@objectstack/spec/ui'; +// `ThemeModeSchema` no longer imported: objectstack#10485 (PR objectstack#10695) +// retired the spec's whole `ui/theme.zod.ts` module, and the objectstack#10856 +// ruling had objectui drop its dangling imports (objectui#5710) — its +// spec-liveness `describe` block left with it. // ============================================================================ // P2.3 Sharing & Embedding @@ -243,19 +246,12 @@ describe('v3.0.10 Spec Protocol New Types', () => { }); }); - describe('ThemeModeSchema', () => { - it('should be a valid Zod schema with parse method', () => { - expect(ThemeModeZod).toBeDefined(); - expect(typeof ThemeModeZod.parse).toBe('function'); - expect(typeof ThemeModeZod.safeParse).toBe('function'); - }); - - it('should validate theme mode values', () => { - expect(ThemeModeZod.safeParse('light').success).toBe(true); - expect(ThemeModeZod.safeParse('dark').success).toBe(true); - expect(ThemeModeZod.safeParse('auto').success).toBe(true); - }); - }); + // `describe('ThemeModeSchema')` DELETED, not rewritten: its whole point was + // that the spec publishes a live `ThemeModeSchema` validator, and + // objectstack#10485 (PR objectstack#10695) retired the spec's entire theme + // module — there is no upstream referent left to assert against + // (objectui#5710). The provider's own mode handling stays covered by + // `packages/providers/src/__tests__/theme-mode-spec-parity.test.tsx`. }); describe('Type re-exports from @object-ui/types index', () => { it('should re-export P2.3 types (compile-time verification)', async () => { diff --git a/packages/types/src/__tests__/phase2-schemas.test.ts b/packages/types/src/__tests__/phase2-schemas.test.ts index 9dcca84ca..7a5596e54 100644 --- a/packages/types/src/__tests__/phase2-schemas.test.ts +++ b/packages/types/src/__tests__/phase2-schemas.test.ts @@ -10,7 +10,6 @@ import { ThemeSwitcherSchema, ThemePreviewSchema, ThemeUnionSchema, - ThemeDefinitionSchema, ReportComponentSchema, ReportBuilderSchema, ReportViewerSchema, @@ -121,11 +120,15 @@ describe('Phase 2: Theme component kinds — Zod Validation', () => { // VALID is now proven REFUSED, so a re-added union member fails here rather // than reappearing silently in the published `@object-ui/types/zod` surface. // - // The theme SYSTEM is untouched — `ThemeDefinitionSchema` (the theme - // document the engine and the provider consume) is retained, and this - // fixture's `themes[0]` still parses against it, which is what makes the - // refusal below attributable to the retired WRAPPER and not to a bad fixture. - it('refuses the retired `type: \'theme\'` component kind, while the theme document it carried still parses', () => { + // The control leg this pin used to carry — `themes[0]` still parsing against + // `ThemeDefinitionSchema` — left with that validator: objectstack#10485 (PR + // objectstack#10695) retired the spec's whole theme module, and the + // objectstack#10856 ruling had objectui remove its re-exports rather than + // keep a local mirror (objectui#5710). Attribution now reads the refusal + // itself: a discriminated union rejecting an unknown `type` reports the + // DISCRIMINATOR, so asserting every issue sits on `type` proves the refusal + // hit the retired wrapper kind, not the theme document it carried. + it('refuses the retired `type: \'theme\'` component kind at the discriminator', () => { const retiredWrapper = { type: 'theme', mode: 'dark', @@ -160,13 +163,19 @@ describe('Phase 2: Theme component kinds — Zod Validation', () => { }; // The wrapper: gone from every union that used to carry it. - expect(ThemeUnionSchema.safeParse(retiredWrapper).success).toBe(false); + const refusal = ThemeUnionSchema.safeParse(retiredWrapper); + expect(refusal.success).toBe(false); expect(AnyComponentSchema.safeParse(retiredWrapper).success).toBe(false); - // The control that makes that refusal mean something: the document the - // wrapper carried is retained and still valid on its own. If this leg ever - // fails, the fixture broke — not the retirement. - expect(ThemeDefinitionSchema.safeParse(retiredWrapper.themes[0]).success).toBe(true); + // Attribution control (see the block comment above): the refusal must sit + // on the `type` discriminator — the retired WRAPPER kind — not somewhere + // inside the theme document the fixture carries. + if (!refusal.success) { + expect(refusal.error.issues.length).toBeGreaterThan(0); + for (const issue of refusal.error.issues) { + expect(issue.path, `refusal must be at the discriminator, got ${JSON.stringify(issue)}`).toEqual(['type']); + } + } }); it('should validate ThemeSwitcherSchema', () => { diff --git a/packages/types/src/__tests__/spec-subschema-parity.test.ts b/packages/types/src/__tests__/spec-subschema-parity.test.ts index 1e0e793ac..2e408da70 100644 --- a/packages/types/src/__tests__/spec-subschema-parity.test.ts +++ b/packages/types/src/__tests__/spec-subschema-parity.test.ts @@ -9,10 +9,12 @@ /** * Sub-schema ↔ @objectstack/spec drift guard (issue #2231, phase 2). * - * The former hand-written mirrors in `zod/objectql.zod.ts` and `zod/theme.zod.ts` - * are now the spec's schemas **by reference** — re-forking one (replacing the - * re-export with a local copy that can drift) is exactly the failure mode that - * produced the original ListViewSchema divergence. These tests pin: + * The former hand-written mirrors in `zod/objectql.zod.ts` are now the spec's + * schemas **by reference** — re-forking one (replacing the re-export with a + * local copy that can drift) is exactly the failure mode that produced the + * original ListViewSchema divergence. (`zod/theme.zod.ts` carried six such + * re-exports too until the spec retired its whole theme module — see the + * retirement block below.) These tests pin: * * 1. Reference identity for every direct re-export. `toBe` — not structural * equality — so a "faithful copy" fails too: a copy is a fork. @@ -34,14 +36,8 @@ import { ColumnSummarySchema as SpecColumnSummarySchema, SelectionConfigSchema as SpecSelectionConfigSchema, PaginationConfigSchema as SpecPaginationConfigSchema, - ColorPaletteSchema as SpecColorPaletteSchema, - TypographySchema as SpecTypographySchema, - BorderRadiusSchema as SpecBorderRadiusSchema, - ShadowSchema as SpecShadowSchema, - ThemeModeSchema as SpecThemeModeSchema, ChartTypeSchema as SpecChartTypeSchema, PageTypeSchema as SpecPageTypeSchema, - ThemeSchema as SpecThemeSchema, } from '@objectstack/spec/ui'; import { HttpMethodSchema, @@ -51,14 +47,6 @@ import { SelectionConfigSchema, PaginationConfigSchema, } from '../zod/objectql.zod.js'; -import { - ColorPaletteSchema, - TypographySchema, - BorderRadiusSchema, - ShadowSchema, - ThemeModeSchema, - ThemeDefinitionSchema, -} from '../zod/theme.zod.js'; import { ChartTypeSchema } from '../zod/data-display.zod.js'; import { PageTypeSchema } from '../zod/layout.zod.js'; @@ -75,17 +63,16 @@ describe('spec sub-schema re-exports are the spec objects (by reference)', () => ['ViewDataSchema', ViewDataSchema, SpecViewDataSchema], ['SelectionConfigSchema', SelectionConfigSchema, SpecSelectionConfigSchema], ['PaginationConfigSchema', PaginationConfigSchema, SpecPaginationConfigSchema], - ['ColorPaletteSchema', ColorPaletteSchema, SpecColorPaletteSchema], - ['TypographySchema', TypographySchema, SpecTypographySchema], - ['BorderRadiusSchema', BorderRadiusSchema, SpecBorderRadiusSchema], - ['ShadowSchema', ShadowSchema, SpecShadowSchema], - // `AnimationSchema` / `ZIndexSchema` pairs REMOVED, not re-pointed: the - // spec deleted both value schemas outright with the `theme.animation` / - // `theme.zIndex` tombstones (objectstack#5021, PR objectstack#5289), and - // this package's re-exports went with them. There is no longer a pair to - // compare on either side — `theme.customVars` is the declared door now. - ['ThemeModeSchema', ThemeModeSchema, SpecThemeModeSchema], - ['ThemeDefinitionSchema', ThemeDefinitionSchema, SpecThemeSchema], + // The six THEME pairs (`ColorPaletteSchema`, `TypographySchema`, + // `BorderRadiusSchema`, `ShadowSchema`, `ThemeModeSchema`, + // `ThemeDefinitionSchema`↔`ThemeSchema`) REMOVED, not re-pointed — the + // same shape as the earlier `AnimationSchema` / `ZIndexSchema` removal + // (objectstack#5021, PR objectstack#5289): objectstack#10485 (ADR-0049, + // PR objectstack#10695) retired the spec's whole `ui/theme.zod.ts` + // module, and the objectstack#10856 ruling had objectui remove its + // re-exports (objectui#5710). There is no longer a pair to compare on + // either side; the describe block at the bottom pins the names OUT of + // `zod/theme.zod.ts` instead. // #2944 — these two were forks that had already drifted, re-exported under // the spec's own symbol name so an importer could not tell them apart. // `ChartTypeSchema` carried 7 of the spec's 19 values and is why #2901 was @@ -102,39 +89,44 @@ describe('spec sub-schema re-exports are the spec objects (by reference)', () => }); /** - * spec v17 (#3494) pruned the never-enforced Theme keys. They were re-exported - * here by reference, so they left with the spec rather than surviving as an - * objectui-only mirror — the second de-facto contract AGENTS.md #0.1 forbids. - * This guards both ends: the keys stay gone from the spec schema, and objectui - * does not quietly grow its own replacements. + * The retired theme schemas stay retired. Two waves of the same shape: + * spec v17 (#3494) pruned the never-enforced Theme keys and their sub-schema + * re-exports left with it (`SpacingSchema` and friends); then + * objectstack#10485 (ADR-0049, PR objectstack#10695) retired the spec's whole + * `ui/theme.zod.ts` module, and the maintainer's ruling on objectstack#10856 + * had objectui REMOVE its six re-exports rather than localize them + * (objectui#5710) — an objectui-only mirror would be the second de-facto + * contract AGENTS.md #0.1 forbids, one repo over from the compatibility + * surface (Option B) that ruling explicitly declined. The per-key + * `SpecThemeSchema.shape` assertions this block used to carry left with the + * spec schema itself — there is no upstream shape left to read. + * + * If a later ruling (e.g. on objectui#5647's theme component kinds) decides + * to localize a theme document schema DELIBERATELY, update this list in the + * PR that records that ruling. */ -describe('spec v17 pruned Theme keys stay pruned (#3494)', () => { - const PRUNED = [ - 'spacing', - 'breakpoints', - 'logo', - 'density', - 'wcagContrast', - 'rtl', - 'touchTarget', - 'keyboardNavigation', - ]; - - it.each(PRUNED)('the spec Theme schema has no `%s` key', (key) => { - const shape = (SpecThemeSchema as unknown as { shape: Record }).shape; - expect( - key in shape, - `spec v17 pruned Theme.${key}; if the spec brought it back, re-export it ` + - `by reference instead of hand-writing a mirror`, - ).toBe(false); - }); - - it('objectui does not re-add a mirror of the pruned sub-schemas', async () => { +describe('retired theme schemas stay retired (#3494, objectstack#10485 / objectui#5710)', () => { + it('objectui does not re-add a local mirror of a retired theme schema', async () => { const themeZod = await import('../zod/theme.zod.js'); - for (const name of ['SpacingSchema', 'SpacingScaleSchema', 'BreakpointsSchema', 'ThemeLogoSchema']) { + for (const name of [ + // spec v17 pruning (#3494) + 'SpacingSchema', + 'SpacingScaleSchema', + 'BreakpointsSchema', + 'ThemeLogoSchema', + // whole-module retirement (objectstack#10485, removal executed as objectui#5710) + 'ColorPaletteSchema', + 'TypographySchema', + 'BorderRadiusSchema', + 'ShadowSchema', + 'ThemeModeSchema', + 'ThemeDefinitionSchema', + 'ThemeSchema', + ]) { expect( name in themeZod, - `'${name}' is gone from @objectstack/spec/ui — do not reintroduce it as an objectui-local schema`, + `'${name}' is gone from @objectstack/spec/ui — do not reintroduce it as an ` + + `objectui-local schema without a maintainer ruling (objectui#5710)`, ).toBe(false); } }); diff --git a/packages/types/src/theme.ts b/packages/types/src/theme.ts index af14eeaaf..df42f66e5 100644 --- a/packages/types/src/theme.ts +++ b/packages/types/src/theme.ts @@ -68,13 +68,14 @@ export type { Shadow } from '@objectstack/spec/ui'; export type { ThemeMode } from '@objectstack/spec/ui'; // `ThemeModeSchema` (the zod value) is intentionally not re-exported — under -// `export type` it was value-erased (#2561); import it from -// `@objectstack/spec/ui` directly when the runtime validator is needed. - -// Import spec types for local use in interfaces below -import type { - ThemeMode, -} from '@objectstack/spec/ui'; +// `export type` it was value-erased (#2561). It can no longer be imported from +// `@objectstack/spec/ui` either: objectstack#10485 (PR objectstack#10695) +// retired the spec's whole `ui/theme.zod.ts` module, and the objectstack#10856 +// ruling had objectui remove its dangling re-exports (objectui#5710). The +// installed `@objectstack/spec` pin still publishes the type re-exports in +// this file; re-homing the theme TYPE surface once the pin moves past the +// retirement is a separate, un-ruled decision — see the tripwire note in +// `packages/providers/src/__tests__/spec-symbol-batch7.test.ts`. /** * Complete Theme Definition — the spec's **authoring** theme shape, re-exported @@ -163,16 +164,17 @@ export interface ThemeSwitcherSchema extends BaseSchema { /** * Theme Preview Component Schema + * + * The `theme` / `mode` members RETIRED with the spec's theme module + * (objectstack#10485; removal ruled on objectstack#10856, executed as + * objectui#5710): their zod validators no longer exist upstream, so keeping + * the members here while `zod/theme.zod.ts` cannot check them would be + * declared-without-enforcement. The kind itself is unregistered and held for + * triage as objectui#5647. */ export interface ThemePreviewSchema extends BaseSchema { type: 'theme-preview'; - /** Theme to preview */ - theme?: Theme; - - /** Preview mode */ - mode?: ThemeMode; - /** Show color palette */ showColors?: boolean; diff --git a/packages/types/src/zod/index.zod.ts b/packages/types/src/zod/index.zod.ts index cc14fb392..69663ec6d 100644 --- a/packages/types/src/zod/index.zod.ts +++ b/packages/types/src/zod/index.zod.ts @@ -284,12 +284,11 @@ export { // Phase 2 Schemas - Theme, Reports, Blocks, and Views // ============================================================================ export { - ColorPaletteSchema, - TypographySchema, - BorderRadiusSchema, - ShadowSchema, - ThemeModeSchema, - ThemeDefinitionSchema, + // `ColorPaletteSchema` / `TypographySchema` / `BorderRadiusSchema` / + // `ShadowSchema` / `ThemeModeSchema` / `ThemeDefinitionSchema` RETIRED with + // the spec's whole `ui/theme.zod.ts` module (objectstack#10485, PR + // objectstack#10695; removal ruled on objectstack#10856, executed as + // objectui#5710) — see `./theme.zod`. // `ThemeComponentSchema` RETIRED in objectui#5489 — see `./theme.zod`. ThemeUnionSchema, ThemeSwitcherSchema, diff --git a/packages/types/src/zod/theme.zod.ts b/packages/types/src/zod/theme.zod.ts index 4d6381d60..866f926ed 100644 --- a/packages/types/src/zod/theme.zod.ts +++ b/packages/types/src/zod/theme.zod.ts @@ -7,79 +7,45 @@ */ /** - * @object-ui/types/zod - Theme Schema Zod Validators + * @object-ui/types/zod - Theme Component Zod Validators * - * Zod validation schemas for theme configuration. - * Aligned with @objectstack/spec UI specification. + * Zod validation schemas for the theme COMPONENT nodes (`theme-switcher` / + * `theme-preview`) — objectui-local declarations, recorded for triage as + * objectui#5647. + * + * The six `@objectstack/spec/ui` theme-schema re-exports that used to live + * here (`ColorPaletteSchema`, `TypographySchema`, `BorderRadiusSchema`, + * `ShadowSchema`, `ThemeModeSchema`, `ThemeDefinitionSchema` — the spec's + * `ThemeSchema`) are RETIRED. objectstack#10485 (ADR-0049 enforce-or-remove, + * PR objectstack#10695) deleted the spec's whole `ui/theme.zod.ts` module — + * values AND types, `AnimationSchema`/`ZIndexSchema` having gone earlier in + * 17.0.0-rc.3 (objectstack#5021) — and the maintainer's ruling on + * objectstack#10856 (2026-08-22, Options A + C) has objectui REMOVE these + * dangling imports; restoring the spec exports (Option B) was explicitly not + * taken. Executed as objectui#5710. + * + * The theme SYSTEM is retained by the same rulings: the `Theme` TYPE surface + * lives in `../theme.ts`, `ThemeEngine` turns a theme document into CSS + * variables, and `ThemeProvider` applies it — none of them consumed these + * runtime validators (measured at objectui#5710). Do NOT hand-write local + * mirrors of the retired schemas here: that localization is a contract + * decision no ruling has taken, and `__tests__/spec-subschema-parity.test.ts` + * pins the retired names out of this module. * * @module zod/theme * @packageDocumentation */ import { z } from 'zod'; -import { - ColorPaletteSchema as SpecColorPaletteSchema, - TypographySchema as SpecTypographySchema, - BorderRadiusSchema as SpecBorderRadiusSchema, - ShadowSchema as SpecShadowSchema, - ThemeModeSchema as SpecThemeModeSchema, - ThemeSchema as SpecThemeSchema, -} from '@objectstack/spec/ui'; import { BaseSchema } from './base.zod.js'; -/** - * Color Palette Schema — `@objectstack/spec/ui` schema re-exported by reference - * (issue #2231; formerly a hand-written mirror). - */ -export const ColorPaletteSchema = SpecColorPaletteSchema; - -/** - * Typography Schema — `@objectstack/spec/ui` schema re-exported by reference - * (issue #2231; formerly a hand-written mirror). - */ -export const TypographySchema = SpecTypographySchema; - -/** - * Border Radius Schema — `@objectstack/spec/ui` schema re-exported by reference - * (issue #2231; formerly a hand-written mirror). - */ -export const BorderRadiusSchema = SpecBorderRadiusSchema; - -/** - * Shadow Schema — `@objectstack/spec/ui` schema re-exported by reference - * (issue #2231; formerly a hand-written mirror). - */ -export const ShadowSchema = SpecShadowSchema; - -// `AnimationSchema` / `ZIndexSchema` RETIRED in @objectstack/spec 17.0.0-rc.3 -// (objectstack#5021 option 2, PR objectstack#5289). `theme.animation` and -// `theme.zIndex` are tombstones now and the spec deleted both value schemas -// outright; `theme.customVars` is the declared door. See `../theme.ts`. - -/** - * Theme Mode Schema — `@objectstack/spec/ui` schema re-exported by reference - * (issue #2231; formerly a hand-written mirror). - */ -export const ThemeModeSchema = SpecThemeModeSchema; - -/** - * Theme Definition Schema — `@objectstack/spec/ui` `ThemeSchema` re-exported by - * reference (issue #2231; formerly a hand-written mirror). `mode` defaults to the - * spec's `'light'` (the old mirror had drifted to `'auto'`). The TS type side - * (`Theme` in `../theme.ts`) is the spec's too, so validator and type agree. - * - * spec v17 (#3494) pruned the never-enforced `spacing`/`breakpoints`/`logo`/ - * `density`/`wcagContrast`/`rtl`/`touchTarget`/`keyboardNavigation` keys; they are - * gone from this schema by reference, and their sub-schema re-exports went with - * them rather than surviving here as an objectui-only mirror. - */ -export const ThemeDefinitionSchema = SpecThemeSchema; - // `ThemeComponentSchema` (`type: 'theme'`) RETIRED in objectui#5489 — the value // side of the interface retired in `../theme.ts`, where the ruling and the -// unregistered-kind measurement are recorded. `ThemeDefinitionSchema` (the -// spec's `ThemeSchema`, the theme DOCUMENT) and `ThemeModeSchema` are retained -// and still exported above: the engine and the provider validate against them. +// unregistered-kind measurement are recorded. Its former retention note kept +// `ThemeDefinitionSchema` / `ThemeModeSchema` exported here "for the engine and +// the provider" — measured stale at objectui#5710: the engine and the provider +// consume the `Theme` / `ThemePreference` TYPES, and no package imported either +// validator. Both left with the spec's theme module (see the header). /** * Theme Switcher Schema @@ -95,11 +61,18 @@ export const ThemeSwitcherSchema = BaseSchema.extend({ /** * Theme Preview Schema + * + * The `theme` / `mode` props RETIRED with the spec's theme module (see the + * header): their validators (`ThemeDefinitionSchema` / `ThemeModeSchema`) no + * longer exist upstream, and hand-writing local mirrors is the localization + * branch the objectstack#10856 ruling left untaken. `BaseSchema` is + * `.passthrough()`, so an authored `theme:` / `mode:` key now passes through + * unvalidated rather than being checked — tolerable only because no renderer + * registers `theme-preview` at all (objectui#5647 measured the kind itself as + * declared-but-unenforced and holds it for triage). */ export const ThemePreviewSchema = BaseSchema.extend({ type: z.literal('theme-preview'), - theme: ThemeDefinitionSchema.optional().describe('Theme to preview'), - mode: ThemeModeSchema.optional().describe('Preview mode'), showColors: z.boolean().optional().describe('Show color palette'), showTypography: z.boolean().optional().describe('Show typography samples'), showComponents: z.boolean().optional().describe('Show component samples'), @@ -116,11 +89,5 @@ export const ThemeUnionSchema = z.discriminatedUnion('type', [ /** * Export type inference helpers */ -export type ColorPaletteSchemaType = z.infer; -export type TypographySchemaType = z.infer; -export type BorderRadiusSchemaType = z.infer; -export type ShadowSchemaType = z.infer; -export type ThemeModeSchemaType = z.infer; -export type ThemeDefinitionSchemaType = z.infer; export type ThemeSwitcherSchemaType = z.infer; export type ThemePreviewSchemaType = z.infer;