Skip to content

fix(types): remove the six retired @objectstack/spec/ui theme-schema re-exports (#5710) - #5713

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5710-theme-zod-dangling-imports
Aug 22, 2026
Merged

fix(types): remove the six retired @objectstack/spec/ui theme-schema re-exports (#5710)#5713
os-zhuang merged 1 commit into
mainfrom
claude/issue-5710-theme-zod-dangling-imports

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#5710

What

Executes the objectui leg of the maintainer's ruling on objectstack-ai/objectstack#10856 (Options A + C, accepted verbatim 「接受所有」): removes the six dangling @objectstack/spec/ui theme-schema imports from packages/types/src/zod/theme.zod.tsColorPaletteSchema, TypographySchema, BorderRadiusSchema, ShadowSchema, ThemeModeSchema, ThemeSchema (re-exported as ThemeDefinitionSchema) — whose upstream module the spec retired whole in objectstack-ai/objectstack#10485 (ADR-0049, PR objectstack-ai/objectstack#10695). The remove branch of "removes/localizes" is taken; no schema body is hand-written locally (rationale below). objectstack#10856 executes the Console pin bump after this lands — no pin is touched here.

Why remove, not localize (measured)

The card anticipated localization "where an engine consumer still needs the shape". Measured on this tree: no engine consumer needs the runtime shape.ThemeEngine / ThemeProvider consume the Theme / ThemePreferencetypes (still resolved via the installed @objectstack/spec 17.1.0 pin); repo-wide, zero non-test code imported any of the six validators from @object-ui/types. The only runtime consumers were ThemePreviewSchema's theme/mode props — a component kind proven unregistered (0 registry hits, 0 fixtures; recorded in #5647, which remains open and is not decided here) — and parity tests whose referent retired. Localizing would recreate, one repo over, the compatibility surface (Option B) the ruling explicitly declined, with no upstream authority left to derive from.

Changes

  • zod/theme.zod.ts — the six spec imports, six re-exports, and their …SchemaType helpers deleted; header rewritten as the retirement record. ThemePreviewSchema loses its theme/mode props: their validators have no upstream successor. BaseSchema is .passthrough(), so those authored keys now pass through unvalidated — tolerable only because nothing renders theme-preview; the kind's own fate stays with finding: ThemeSwitcherSchema / ThemePreviewSchema are the same dead component kind #5489 retires — theme-switcher and theme-preview are registered by nothing either #5647, which remains open.
  • zod/index.zod.ts — the six names leave the barrel (tombstone comment).
  • theme.ts — the matching theme/mode interface members removed (keeping them while zod cannot check them would be declared-without-enforcement); the stale "import ThemeModeSchema from the spec directly" guidance replaced with the retirement record. The theme type re-exports (Theme, ThemeMode, ColorPalette, …) are deliberately untouched — see the follow-up finding below.
  • __tests__/spec-subschema-parity.test.ts — the six by-reference pairs removed (no referent on either side); the [ci] scripts/ 在零 tsconfig 覆盖内:turbo type-check 从不检查 scripts/__tests__/*.ts——一批门禁 pin 测试自身无类型门 #3494 pruning pin and this retirement folded into one guard pinning all retired theme-schema names out of zod/theme.zod.ts, so a local mirror cannot reappear without a ruling.
  • __tests__/phase2-schemas.test.ts — the retired-wrapper pin's attribution control (ThemeDefinitionSchema.safeParse(themes[0])) left with that validator; the refusal is now attributed via the discriminated union's own error: every issue must sit on path ['type'], proving the refusal hits the retired wrapper kind, not the fixture's theme document.
  • __tests__/p2-spec-exports.test.ts — the ThemeModeSchema spec-liveness block deleted with a tombstone (its whole point was that the spec publishes the validator; it no longer does).
  • changeset@object-ui/types minor (breaking semantics stated in the body, per the repo's version-alignment convention; never major).

Verification

At 64e469a (this PR's head):

  • pnpm --filter @object-ui/types build && type-check && lint && pnpm exec vitest run packages/types/ — all green under the container verify lock: 43 test files / 474 tests passed, lint 0 errors, os-verify-lock: VERDICT command-exit 0.
  • Gate instrument (the Console Pin Gate fails on named value imports of retired spec exports in the SPA bundle graph — type-only imports are erased at emit): an AST-level sweep of all packages/**/apps/** sources for value-level import {…} from '@objectstack/spec/ui' of the six names reported 6 sites in theme.zod.ts + 1 in p2-spec-exports.test.ts before this change and 0 after (2 remaining hits are packages/providers/__tests__ files — not in any bundle graph, deliberately left, see below). Built dist/zod/theme.zod.js now imports only zod and ./base.zod.js; the six names appear in dist only inside comments.
  • The six really are gone upstream: on objectstack origin/main95437e7, each name has 0 exports under packages/spec/src/ui/ while controls PageSchema/FormViewSchema return live hits; packages/spec/src/ui/ contains no theme file at all.
  • Reverse verification of the new retirement pin (trap-guarded mutation, restore proven on disk): re-adding export const ThemeModeSchema = z.enum([...]) to theme.zod.ts (mutation confirmed on disk: marker grep count 1) turned spec-subschema-parity.test.tsred (1 failed / 13 passed, exit 1) on exactly that name; after trap restore (marker count 0, git status clean) the file is green again (14/14).
  • Cheap CI gates run locally at the same commit, each quoting its own verdict line: check:spec-symbols ✅, check:phantom-deps ✅, check:esm-specifiers ✅, check:control-bytes ✅, check:self-import ✅, check:action-forward-parity (exit 0), check-changeset-presence ✅, check-changeset-fixed ✅, check-changeset-no-major ✅.
  • Declared narrowing: full pnpm type-check / pnpm test / pnpm lint across all 40 packages was not run locally — the repo-wide grep for the six removed names shows zero consumers outside packages/types, so the affected-package run above is the superset for this diff; CI runs the full farm regardless.

Deliberately out of scope (measured, filed separately)

  • packages/providers: src/types.ts reads (typeof ThemeModeSchema)['_zod']['input']type-only (erased at emit — cannot redden the pin gate), and two test files import the schema as a value (tests are outside every bundle graph). All three compile against the installed 17.1.0 pin and their own comments declare spec-retirement a re-triage tripwire. Re-homing the theme TYPE surface is an un-ruled decision — filed as a follow-up issue together with theme.ts's type re-exports.
  • packages/app-shell/src/views/metadata-admin/clientValidation.ts:590 reads (await import('@objectstack/spec/ui')).ThemeSchema at runtime — dangling against the framework tree but invisible to the pin gate (namespace property access, not a named import binding) and unreachable (theme is not a registered metadata type). Out of this card's fence (packages/app-shell/**); filed separately.
  • content/docs/core/theme-schema.mdx falsehoods are already held by content/docs/core/theme-schema.mdx teaches a schema that does not exist — six independent falsehoods, now including the type: 'theme' kind #5489 retires #5648; no docs touched here (measured: no docs/examples reference the six removed names).

Generated by Claude Code

…re-exports (#5710)
objectstack#10485 (ADR-0049, PR objectstack#10695) retired the spec's whole
ui/theme.zod.ts module; the maintainer's ruling on objectstack#10856
(Options A + C) has objectui remove its six dangling imports first so the
Console Pin Gate can build objectui against the framework tree.
- zod/theme.zod.ts: drop the six spec imports, the six re-exports and their
...SchemaType helpers; drop ThemePreviewSchema's theme/mode props (their
validators have no upstream successor; the kind itself is unregistered and
held for triage as objectui#5647 — not decided here)
- zod/index.zod.ts: drop the six names from the barrel, tombstone comment
- theme.ts: drop the matching interface members; retire the stale
"import ThemeModeSchema from the spec directly" guidance
- spec-subschema-parity.test.ts: remove the six by-reference pairs (no
referent left on either side); fold the #3494 pruning pin and the new
whole-module retirement into one "retired names stay out of theme.zod"
guard
- phase2-schemas.test.ts: the retired-wrapper pin now attributes the refusal
via the union discriminator instead of the retired ThemeDefinitionSchema
- p2-spec-exports.test.ts: delete the ThemeModeSchema spec-liveness block
(its referent retired upstream)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EuPCi56cnGyykygi3z9w4m
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3914.3 KB3990.2 KB
Main entry chunk (gzip)152.2 KB350 KB
Entry fileindex-DHs6kHQ8.js
StatusPASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.04KB3.72KB
app-shell (runtime-config.js)12.80KB4.47KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)29.34KB7.05KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)9.63KB3.74KB
auth (index.js)2.77KB1.22KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.02KB0.89KB
auth (useIsWorkspaceAdmin.js)3.04KB1.45KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)507.01KB113.85KB
core (index.js)4.92KB1.97KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)160.15KB44.52KB
fields (index.js)238.40KB59.89KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.65KB18.32KB
plugin-chatbot (index.js)181.41KB43.22KB
plugin-dashboard (index.js)128.41KB32.95KB
plugin-designer (index.js)212.30KB42.80KB
plugin-detail (index.js)242.34KB60.98KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)125.63KB30.64KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)200.79KB54.26KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.80KB27.20KB
plugin-map (index.js)20.06KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.61KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)43.66KB14.77KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.33KB0.69KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (index.js)4.77KB2.16KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)10.76KB3.17KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)6.92KB2.40KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.59KB1.79KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-zhuang@claude