Skip to content

refactor(app-shell): delete the dead metadataConverters module - #6265

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-6224-delete-dead-metadataconverters
Aug 25, 2026
Merged

refactor(app-shell): delete the dead metadataConverters module#6265
yinlianghui merged 2 commits into
mainfrom
claude/issue-6224-delete-dead-metadataconverters

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#6224

Deletes packages/app-shell/src/utils/metadataConverters.ts (139 lines). No other production change.

Why this is a delete, not a shrug

The module is not merely unused — it is a copy-paste source for two defects this lane repaired hours ago, and it is exactly the file a future author looking for "the converter" would find and revive:

Both patterns were re-read in the file at 9b61cf199 before writing this, so the argument is about today's code, not the code the finding was filed against. Enforce-or-remove: dead code carrying wrong patterns is worse than dead code.

Verification — and why the green suite is not the evidence

⚠️A deletion card's "green" is weak evidence. Nothing turns red when unused code disappears, so a passing suite does not confirm the module was unused; it only confirms nothing that runs today touched it. There is no red-turning-green test to show here, and constructing one would be theatre. The evidence is the two measurements below.

1. Zero importers, measured with two working positive controls

A grep that finds nothing is indistinguishable from a grep that is wrong, so the instrument was proven first.

ModuleReferencing lines outside its own file (same grep shape, *.ts/*.tsx, excluding node_modules/dist)
services/MetadataService.ts (control)25 files
utils/appRoute.ts (control, same directory)60
utils/resolveViewId.ts (control, same directory)18
utils/crudAffordances.ts (control, same directory)5
utils/metadataConverters.ts0

Widening the sweep past static imports, as the card asked:

  • Whole-repo grep for metadataConverters across all file types returns only prose — CHANGELOG.md entries, ROADMAP.md lines 1000/1006. Zero source hits.
  • Dynamic reach: no require(...), no dynamic import(...), and no template-literal import path mentions the module anywhere in the repo. packages/app-shell/src contains no require( at all.
  • Tests: no test imports it. (A test-only importer would still be an importer; there is none.)
  • The two toObjectDefinition hits in packages/plugin-designer/src/MetadataObjectsPage.tsx are its own local function toObjectDefinition(raw: ServerObjectSchema) at line 85, not an import of this module — an independent same-named function, which is itself the duplication this card is about.

2. No published re-export — which is what makes this a patch

  • packages/app-shell/src/index.ts: no mention of metadataConverters, toObjectDefinition, or toFieldDefinition.
  • packages/app-shell/src/utils/index.ts (the barrel the package root re-exports from): same, zero hits across all 112 lines.
  • packages/app-shell/package.jsonexports declares exactly two subpaths: "." and "./styles.css".
  • Checked against the freshly builtdist/index.d.ts (not a stale one): zero hits for all three symbols, while a control grep for two symbols that are published (resolveHostAppSegment, MetadataDirectoryPage) hits.

Worth naming: the module did compile into dist/utils/metadataConverters.{js,d.ts} and therefore shipped in the tarball (files: ["dist"]). It was still unreachable — the exports map refuses every subpath except the two above, so no external consumer could deep-import it. Removing shipped-but-unreachable bytes is not a breaking change, which is why this is a patch and not the minor-with-a-loud-changeset shape #6011 had.

3. The type-check oracle, with the closure built first

⚠️tsc resolves workspace deps through dist while vitest.config.mts aliases @object-ui/* to src/, so a red here can be an unbuilt sibling rather than a real consumer. The closure was built first, both runs were --force (a cached turbo green is not a measurement), and the stale dist/utils/metadataConverters.{js,d.ts} were deleted before the post-deletion run — otherwise a consumer resolving through dist would have type-checked green against a file that no longer exists in src.

RunResult
Baseline, before deletion (turbo run type-check --filter='...@object-ui/app-shell' --force)Tasks: 39 successful, 39 total · Cached: 0 cached
After deletion, stale dist removed, same commandTasks: 39 successful, 39 total · Cached: 0 cached · zero error TS… lines

Scope of that filter is the downstream direction (prefix ...pkg): @object-ui/app-shell itself plus its three consumers — @object-ui/console, @object-ui/example-byo-backend-console, @object-ui/example-console-starter.

No hidden consumer surfaced, so the card's fork clause was not triggered.

4. Proving the oracle can fail

A green type-check only means something if it could have gone red. A probe file importing the deleted specifier was added to packages/app-shell/src/utils/, its landing on disk confirmed by grepping for both the injected marker and the import specifier (an editor's exit code is not evidence a write landed), then pnpm --filter @object-ui/app-shell type-check:

src/utils/__oracle_control_6224.ts(1,35): error TS2307: Cannot find module
'./metadataConverters.js' or its corresponding type declarations.
Exit status 2

Exactly one error, on the probe. The probe was restored under trap … EXIT INT TERM using absolute paths, and the restore was verified, not assumedgit diff HEAD --stat afterwards showed only the intended deletion (1 file changed, 139 deletions(-)).

5. Tests

pnpm exec vitest run packages/app-shell/src/utils --maxWorkers=2, run from the repo root (objectui#3378: the --filter/cd-into-package forms either refuse loudly or silently run apps/console's 22 files and report them green):

Test Files 26 passed (26)
Tests 453 passed (453)

Sanity-checked against the target's own count: find packages/app-shell/src/utils -name '*.test.ts*' = 26, matching — so this is app-shell's utils, not another package's suite.

Declared narrowing: app-shell's full suite is 524 test files; this run covers the 26 under the deleted file's own directory. CI's 4-shard test job runs the rest either way, and the blast radius is measurably zero — no file in the repo imports the module by any static or dynamic route, so no test can transitively load it.

6. Gates

Derived by enumerating each CI job's own step list (ci.yml, lint.yml, changeset-presence.yml, control-bytes.yml, readme-exports.yml, node-esm-load-gate.yml) against the two files this PR actually changes. Verdict lines below are the gates' own, re-run at final HEAD 4473c3149:

  • check-changeset-presence — measured red → green, the one real red-to-green in this PR. Before: "❌ 1 source file(s) of 1 released package(s) changed, and this change adds no changeset: @object-ui/app-shell". After: "✅ 1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)". The gate decided the changeset is owed; the patch scoring follows from §2.
  • check-changeset-no-major"✅ No changeset declares a major bump."
  • check-changeset-fixed"✅ All workspace packages are in the changeset fixed group."
  • check-control-bytes"✅ OK (scanned 5168 tracked text file(s); skipped 85 binary)."
  • check-readme-exports"✅ OK … 378 self-imports judged (378 real, 0 wrong-path, 0 fabricated) … 0 unbuilt". This one first came back red with 5 unjudgeable self-imports in @object-ui/cli and @object-ui/plugin-ai"its type entry ./dist/index.d.ts is not on disk". That is the unbuilt-sibling artefact, not this change; rather than assume so, those two packages were built and the gate re-measured green. app-shell's README never mentioned the removed symbols.
  • check-designer-field-key-parity"designer-field-key-parity: OK" (run because the module models designer field defs).
  • check-phantom-dependencies"✅ Every in-scope import is declared by the package that publishes it." (the deleted file's only import was @object-ui/types, which app-shell still uses widely).
  • check-package-self-import"✅ No package names itself inside its own src/."
  • check-spec-symbol-derivation"✅ spec alignment claims: 2 declared deliberate copies, 18 unbacked claims in 5 packages."
  • check-node-esm-load --specifiers-only"Specifier leg: no un-ledgered package emits an extensionless relative specifier."
  • check-lint-coverage"✅ 46/46 packages linted, 0 with outstanding errors."
  • check-type-check-coverage"✅ 41/41 packages compile their tests, 0 declared debt."
  • pnpm --filter @object-ui/app-shell lint (eslint .) — "✖ 2678 problems (0 errors, 2678 warnings)"; zero errors, warnings are the package's pre-existing no-explicit-any baseline.
  • Full repo build (turbo run build --filter='!@object-ui/site') — "43 successful, 43 total".

What would still pass on a revert

Stated plainly, because it is the honest weakness of a deletion card: every assertion in this repo would still pass if this commit were reverted. Nothing tests the deleted module, which is precisely the finding. The claim this PR makes is not "a test now passes" but "nothing reaches this code" — and that claim rests on the positive-control greps (§1), the published-surface check against a freshly built dist (§2), the downstream type-check with a built closure and stale dist cleared (§3), and the oracle control proving that type-check would have gone red on a real consumer (§4). The one genuine red-to-green here is check-changeset-presence (§6).

Out of scope

The issue's "adjacent, same family" note — packages/plugin-dashboard/src/recordFields.tsx:56 reading def.isSystem === true || def.system === true, where the isSystem half can never fire on a spec-parsed field def — is not addressed here; it is live code in another package and stays open on #6224's thread for triage. packages/plugin-designer/src/MetadataObjectsPage.tsx's independent local toObjectDefinition is likewise untouched.

Collision check

packages/app-shell/src/utils/ is this card's lane. #6165's HomeRail consumers do live in app-shell, but under packages/app-shell/src/console/home/ (HomeRail.tsx, HomePage.tsx, plus tests) — different files, no file-level overlap with the single file this PR removes. No overlap with #6176 (plugin-form), #6167 (examples/schema-catalog, apps/site), or #5935 (components, plugin-list, plugin-detail, the lucide gate script).


Generated by Claude Code

`packages/app-shell/src/utils/metadataConverters.ts` has zero importers,
is not re-exported from the package barrel, and no `exports` subpath
reaches it. Enforce-or-remove: it is not merely unused, it is a
copy-paste source for two defects this lane just repaired --- a
name-heuristic `isSystem` and a three-way `referenceTo` tolerance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3223.0 KB3266.6 KB
Main entry chunk (gzip)153.8 KB350 KB
Entry fileindex-KpDPTf2A.js
StatusPASS

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


📦 Bundle Size Report

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.38KB3.90KB
app-shell (runtime-config.js)18.10KB6.51KB
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)505.63KB114.68KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)171.74KB47.48KB
fields (index.js)238.40KB59.89KB
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)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.21KB44.67KB
plugin-dashboard (index.js)133.35KB34.45KB
plugin-designer (index.js)212.33KB42.81KB
plugin-detail (index.js)244.74KB62.20KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)126.39KB30.80KB
plugin-gantt (index.js)164.17KB39.89KB
plugin-grid (index.js)201.14KB54.40KB
plugin-kanban (index.js)52.89KB14.59KB
plugin-list (index.js)111.94KB27.24KB
plugin-map (index.js)20.11KB6.64KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)9.26KB3.13KB
plugin-view (index.js)84.55KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)54.84KB18.43KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
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)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
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)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.49KB2.14KB
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

@yinlianghui
yinlianghui marked this pull request as ready for review August 25, 2026 06:24
@yinlianghui
yinlianghui added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit dc14bcbAug 25, 2026
28 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-6224-delete-dead-metadataconverters branch August 25, 2026 06:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants

@yinlianghui@claude