fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text - #7005

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance
Aug 31, 2026
Merged

fix(types): the remaining 11 ADR-0049 tombstones carry their remediation text#7005
os-sam merged 1 commit into
mainfrom
claude/issue-6931-tombstone-guidance

Conversation

@claude

@claudeclaudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes#6931

retirementTombstone() (added by #6930 for #6105) writes a guidance string once into both author-facing channels — z.never({ error }), the parse-time issue message, and .describe(), the generated JSON-Schema and docs surface. Nine tombstones were converted there; eleven were left on the bare z.never().optional().describe(...) spelling and kept answering with zod's own Invalid input: expected never, received string. This converts the remaining eleven.

Five of them sat on StaticTableColumnSchema — the object #6105 half-fixed — so its author read guidance on nine keys and zod's generic on five: a shape that teaches the message means something, then withholds it.

Population, re-derived on this branch (not taken from the card)

z.never( over packages/types/src/zod/** = 18 hits: 5 prose in doc comments, 1 the helper's own body (tombstone.zod.ts), 1 already carrying { error } (complex.zod.tsDashboardConfigSchema.aria, #5852) — leaving 11 generic call sites. That matches the card's 21 / 1 / 9 / 11 exactly (the card counted 21 declarations pre-#6930; the nine it converted no longer grep as z.never(). After this PR, zero z.never().optional().describe( remain anywhere under packages/types/src/zod/.

wheremembers
StaticTableColumnSchemaheaderIcon, fitContent (#6424), format, options, currency (#6425)
TableSchemahoverable, striped (#5474)
TimelineSchematimeScale (#6355)
MenuItemSchema, both union armstype (#6523)
ActionSchemaconfirm (#4314) — the key that ESTABLISHED the convention, and the last one still emitting the generic message

The accept set does not move (the inherited constraint from #6105)

Module resolution: the probe imported the source modules (packages/types/src/zod/*.zod.ts) through tsx; packages/types/dist does not exist in this worktree (ls reports no such file), so no built artefact could have been read. The same probe ran before and after the edit.

26 probes — the 11 conversions, the 9 already-converted keys as cross-contamination controls, and 6 live-value controls (live column, live static table, live gantt timeline, command item, divider, confirmText action):

  • accept-set moves: 0. Every probe reports the same success, the same issue path, the same issue code (invalid_type) and the same expected (never) before and after — including the nested per-arm issue structure of the MenuItemSchema union.
  • messages changed: 11 (exactly the targets). messages identical: 15 (the 9 already-converted keys plus the controls' green parses).
  • .description: 132 members compared byte-for-byte across the five affected schemas, 0 drifts.retirementTombstone() passes the same string .describe() already carried.

Sample of the author-visible change (what packages/cli's validate / check print verbatim):

memberbeforeafter
StaticTableColumnSchema.currencyInvalid input: expected never, received stringNOT on the static table surface (objectui#6425) — declared on the rich TableColumn only; use data-table
TableSchema.stripedInvalid input: expected never, received booleanRETIRED (objectui#5474) — the static table never implemented striping; style rows via className, or use data-table
TimelineSchema.timeScaleInvalid input: expected never, received stringRETIRED (objectui#6355) — author scale instead
ActionSchema.confirmInvalid input: expected never, received objectRETIRED (objectui#4314) — author confirmText instead

z.never({ error }) was kept, per the card: the refine route would report custom instead of invalid_type, which is an observable contract change.

One honest nuance — MenuItemSchema is a union

Its top-level issue is still zod's own invalid_union / Invalid input at path []; the converted guidance rides the per-arm issues underneath it. That is a property of the union, not of the tombstone, and the objectui CLI prints only top-level issues — so for these two members the improvement reaches consumers that walk arm errors and the .describe() metadata, not the CLI's printed line. Rather than gloss it, the union's shape is pinned in menu-item-union.test.ts and documented at the declaration, so nobody later reads the unchanged top-level message as a failed conversion. Filed separately as the CLI-side gap: #7004.

Routing re-checked, member by member (not assumed to follow #6930)

Measured against @objectstack/spec@17.2.0 in this worktree:

The #6930 scope-boundary pin: flipped, not deleted

static-table-narrow-surface.test.ts asserted that seven members (the five #6424/#6425 arrivals plus hoverable/striped) still emittedZOD_GENERIC_NEVER, so #6105's untouched half was a recorded decision with a red test behind it. That assertion is now stale by construction. It is flipped in the same commit — same test, same seven members, now held to the standard the nine already meet (guidance present, generic absent, message derived-equal to .describe(), codeinvalid_type, path[key]), with the live column and live table as in-test non-vacuity controls. Deleting it would have removed a guard.

Added beside it: a literal pin on striped (the twin of the existing align literal, so the derived assertions cannot all drift together), and guidance assertions in timeline-timescale-retired.test.ts, menu-item-union.test.ts and phase2-schemas.test.ts for the members that live outside this file.

Verification

All commands run from the repo root, root-relative paths, on 3a9826149 (the final commit):

  • pnpm exec vitest run on the four affected test files → Test Files 4 passed (4) · Tests 89 passed (89) (4 paths passed, 4 files reported).
  • pnpm exec vitest run packages/types/ packages/components/src/__tests__/menu-item-separator-dialect.test.tsxTest Files 79 passed (79) · Tests 968 passed (968).
  • pnpm --filter @object-ui/types type-check → exit 0; the script echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, so the new test code is type-checked too.
  • pnpm --filter @object-ui/types lint (plain form) → ✖ 260 problems (0 errors, 260 warnings), exit 0 — all warnings are pre-existing no-explicit-any warnings on the z.ZodType lazy declarations this PR does not touch.
  • node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).
  • pnpm check:control-bytes✅ check-control-bytes: OK (scanned 5814 tracked text file(s); skipped 85 binary).
  • pnpm check:esm-specifiers → exit 0, no un-ledgered package emits an extensionless relative specifier (this PR adds two ./tombstone.zod.js imports).
  • pnpm check:spec-symbols✅ spec symbol derivation: 1325 files scanned …, 0 untriaged collisions.

Reverse verification (predicted RED, observed RED). With the four test files kept and the three source files reverted to a5a799d63, the four files report 5 failed | 84 passed — exactly the flipped pin, the striped literal, and the three new guidance assertions. The mutation was confirmed on disk by blob hash (each file's git hash-object equal to the base blob and unequal to the HEAD blob, never an empty hash), the restore leg used git checkout HEAD with absolute paths under an EXIT/INT/TERM trap, and restoration was proven by hash equality with the HEAD blobs plus an empty git diff HEAD. No build leg was involved or needed: these tests import the modules by relative source path and packages/types/dist does not exist.

Lint scope: the repo-wide scan belongs to CI; the run above is a narrowed one, and the narrowing is measurable rather than assumed — the population came from eslint's own config (packages/types' lint script is eslint ., which linted the whole package, 260 warnings spread across files this PR never touches), the changed-file count came from --format json (7 files), and the config makes the narrowing sound: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project / projectService, so type-aware linting is off and an edit inside packages/types cannot move any untouched file's verdict.


Generated by Claude Code

…ion text
`retirementTombstone()` (objectui#6105 / PR #6930) writes a guidance string
ONCE into both author-facing channels — `z.never({ error })`, the parse-time
issue message, and `.describe()`, the generated JSON-Schema and docs surface.
Nine tombstones on `StaticTableColumnSchema` were converted there; eleven
declarations were left on the bare `z.never().optional().describe(...)`
spelling and kept answering with zod's generic `Invalid input: expected never,
received string` — which names the key and says nothing about why it was
retired or what to write instead.
Five of the eleven sat on `StaticTableColumnSchema` itself, so its author read
guidance on nine keys and zod's generic on five: a shape that teaches the
message means something, then withholds it. Converted here:
`headerIcon` / `fitContent` / `format` / `options` / `currency`
(StaticTableColumnSchema), `hoverable` / `striped` (TableSchema), `timeScale`
(TimelineSchema), `type` on both `MenuItemSchema` union arms, and `confirm`
(ActionSchema) — the key that established the convention and was the last one
still emitting the generic message.
The accept set does not move. Measured member-by-member on the SOURCE modules
(tsx; `packages/types/dist` does not exist in a fresh worktree): for all 11
conversions, the 9 already-converted controls and 6 live-value controls,
`safeParse` reports the same `success`, `path`, `code` (`invalid_type`) and
`expected` (`never`) before and after; only the message differs. All 132
`.description` values on the five affected schemas are byte-identical.
`MenuItemSchema` is a union, so its top-level issue stays zod's own
`invalid_union` / `Invalid input` at path `[]` and the guidance rides the
per-arm issues; that is pinned in the tests rather than glossed.
#6930's scope-boundary pin — which asserted the remaining seven still emitted
the generic message — is flipped rather than deleted: it now holds them to the
same standard as the nine, with the live column and table as in-test
non-vacuity controls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3180.2 KB3222.7 KB
Main entry chunk (gzip)143.6 KB350 KB
Entry fileindex-C9ZECNEe.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)12.46KB4.71KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
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)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
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.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
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)512.08KB116.42KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)177.67KB49.45KB
fields (index.js)243.65KB61.63KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
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)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
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)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.53KB45.18KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)247.26KB63.17KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.11KB32.61KB
plugin-gantt (index.js)165.21KB40.37KB
plugin-grid (index.js)202.08KB54.61KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)29.05KB8.37KB
plugin-tree (index.js)8.98KB3.08KB
plugin-view (index.js)85.79KB21.10KB
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)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)3.11KB1.48KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
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)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.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 (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
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 (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
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-sam@claude