Skip to content

Repair five retired lucide spellings that reach the icons-record resolver - #5638

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-5622-retired-lucide-spellings
Aug 21, 2026
Merged

Repair five retired lucide spellings that reach the icons-record resolver#5638
os-sales merged 1 commit into
mainfrom
claude/issue-5622-retired-lucide-spellings

Conversation

@claude

@claudeclaudeBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Fixes#5622

lucide retires a spelling by dropping it from its runtime icons record while keeping it as a deprecated named export. A retired name therefore still imports, still type-checks, and still renders wherever it is used as a component — and resolves to null wherever it is used as a string, because every string lookup here reads that record. Nothing goes red in either direction. This repairs the five names on that path, plus the two retired fixture spellings, and pins each against record membership.

Scope is half 1 only, exactly as triage split it. The repo-level icon:-literal gate is not implemented here — it is tracked separately in #5633, which remains open.

Membership probe re-run at claim time

Triage required this be re-measured rather than inherited, since the card exists because a name's membership moved underneath a working site.

  • Installed lucide-react@1.31.0, resolved from packages/components (single copy in the store: node_modules/.pnpm/lucide-react@1.31.0_react@19.2.8).
  • icons record carries 1767 entries.
  • Probe replicates the consumers' own path: toPascalCaseiconNameMap ({ Home: 'House' }) → key in icons.
sitespellingrecord keyin record
DetailView mobile EditeditEditno
→ repairedsquare-penSquarePenyes
ui:icon declared defaultsmileSmileno
→ repairedface-slightly-smilingFaceSlightlySmilingyes
DeclaredActionsBar fixturecheck-circleCheckCircleno
→ repairedcircle-check-bigCircleCheckBigyes
DeclaredActionsBar fixturex-circleXCircleno
→ repairedcircle-xCircleXyes
plugin-listVIEW_ICONSGrid / GanttChartSquare / BarChart3no (all three)
→ repairedGrid3x3 / ChartGantt / ChartColumnyes (all three)

The measurement reproduces the issue body's table unchanged at this version.

Cited line numbers, re-derived on current origin/main

All three verified by code, exact:

  • packages/plugin-detail/src/DetailView.tsx784icon: 'edit' (item sys_edit_mobile at 782) ✅
  • packages/components/src/renderers/basic/icon.tsx83icon: 'smile', and 86defaultValue: 'smile'
  • packages/plugin-list/src/ViewSwitcher.tsxGrid at 13, GanttChartSquare at 18, BarChart3 at 20, inside the cited 13–21 ✅

The smile replacement — my product pick

face-slightly-smiling, and the reason is that it is not a redesign. Smile === FaceSlightlySmiling is true on the installed lucide — the record's own spelling points at the very same glyph object — so the designer palette entry and a freshly dropped icon component look exactly as they always did. The defect was that the palette glyph was blank and a dropped icon rendered nothing plus a console.warn; the fix restores the intended appearance instead of choosing a new default look. Picking an unrelated live name (sticker, star, shapes all resolve) would have silently changed what the default icon component is while fixing a spelling bug — a larger, unasked change.

Both spots move together — the registration icon: and the name input's defaultValue. Repairing one alone leaves either the default rendering nothing or the palette glyph blank, so a pin asserts the two stay equal.

gantt is the one real glyph change

GanttChartSquare is genuinely a different object from ChartGantt (the identity-preserving live spelling is SquareChartGantt, and GanttChartSquare === SquareChartGantt is true). ChartGantt is chosen anyway so both switchers draw the same glyph for the same ViewType: packages/plugin-view/src/ViewSwitcher.tsx landed grid: Grid3x3, gantt: ChartGantt, chart: ChartColumn in #5586. One view type drawing two different icons depending on which switcher is on screen is the drift worth avoiding.

The pins go red on the unrepaired spellings

Four pins assert icons-record membership, not resolvability — which is the whole point. Every retired spelling repaired here is the same component object as its replacement (Edit === SquarePen, Smile === FaceSlightlySmiling, Grid === Grid3x3, BarChart3 === ChartColumn, CheckCircle === CircleCheckBig, XCircle === CircleX are all true), so a pin that rendered the glyph or reached for the export would pass on the broken name. That is precisely the blindness that let this ship.

Verified by ablation — production spellings reverted to the retired ones, mutation confirmed on disk by anchored grep -c counts on both the injected and the removed text, restored by an EXIT/INT/TERM trap:

mutation confirmed on disk: P1 edit=1 square-pen=0 | P2 code-smile=2
P3 <Grid=1 <GanttChartSquare=1 <BarChart3=1
P4 check-circle=1 x-circle=1
Test Files 4 failed (4)
Tests 5 failed | 25 passed (30)

The four membership assertions that went red:

  • components → "names only live icons keys, on BOTH surfaces"
  • plugin-detail → "names only live icons keys"
  • plugin-list → "names only live icons keys"
  • app-shell → "names only live icons keys" (plus one incidental testid assertion in the same suite)

Repeated twice with identical results; RESTORE CONFIRMED: tree clean on both runs. No rebuild leg applies here: every pin reads its subject through a relative source import (../renderers/basic/icon) or an explicit src/readFileSync, never through dist/.

DOM-leak ledger — no row edit owed

packages/components/src/renderers/** is now under the ledger (#5574). This change touches only the ui:iconregistration metadata (icon: and the input's defaultValue), not the renderer's emitted markup, so the attribute set is unmoved:

packages/app-shell/src/__tests__/widget-dom-leak-sweep.test.tsx
Test Files 1 passed (1)
Tests 200 passed (200)

ui:icon stays ledgered as BARE_SPREAD_ON_SVG with camelCase preserved — same case as the sibling round-9 PR that changed only text content.

Verification

All gates run against the final commit 46b096008, working tree clean.

  • Pinspnpm vitest run from the repo root (package-cwd is refused by the repo's guard, objectui#3378): Test Files 4 passed (4), Tests 30 passed (30).
  • DOM-leak sweepTests 200 passed (200).
  • type-check@object-ui/components, plugin-detail, plugin-list, app-shell all pass; all four script names echoed in the output, so this is not a zero-match silent pass.
  • Changesetcheck-changeset-presence.mjs, exit 0, verdict line: ✅ 7 source file(s) of 4 released package(s) changed, and this change declares 1 changeset(s): .changeset/retired-lucide-spellings-5622.md.
  • Lint — the 7 changed .ts/.tsx files, eslint --no-inline-config: 0 errors, 62 warnings, every one pre-existing no-explicit-any on lines this diff does not touch. Narrowed deliberately, and the narrowing is a measurement rather than a gap: file count 7 read from --format json, and type-aware linting is not enabled (no projectService / parserOptions.project in eslint.config.js), so a per-file verdict cannot move for any file this diff does not touch. CI runs the full farm regardless.
  • No raw control bytes in any changed file.

Generated by Claude Code


Generated by Claude Code

…-record resolver (#5622)
lucide retires a spelling by dropping it from its runtime `icons` record while
keeping it as a deprecated named export, so a retired name still imports, still
type-checks and still renders as a COMPONENT — and resolves to null wherever it
is used as a STRING. Nothing goes red either way.
- plugin-detail: DetailView's mobile Edit action 'edit' -> 'square-pen'
- components: the ui:icon renderer's own default 'smile' ->
'face-slightly-smiling', in BOTH the registration icon and the name input's
defaultValue
- plugin-list: ViewSwitcher's VIEW_ICONS Grid -> Grid3x3, BarChart3 ->
ChartColumn, GanttChartSquare -> ChartGantt
- app-shell: the DeclaredActionsBar fixtures 'check-circle' -> 'circle-check-big'
and 'x-circle' -> 'circle-x'
Four resolvability pins assert icons-record MEMBERSHIP rather than
resolvability: every retired spelling here is the SAME object as its
replacement, so a render- or export-based assertion passes on the broken name.
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

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

Size Limits

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

@os-sales
os-sales marked this pull request as ready for review August 21, 2026 21:37
@os-sales
os-sales added this pull request to the merge queueAug 21, 2026
Merged via the queue into main with commit 42887e0Aug 21, 2026
23 checks passed
@os-sales
os-sales deleted the claude/issue-5622-retired-lucide-spellings branch August 21, 2026 21:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant

@os-sales