Skip to content

refactor(layout): remove the unread logo key from AppShellBranding - #5366

Merged
os-support-ai merged 1 commit into
mainfrom
claude/issue-4818-appshellbranding-logo
Aug 20, 2026
Merged

refactor(layout): remove the unread logo key from AppShellBranding#5366
os-support-ai merged 1 commit into
mainfrom
claude/issue-4818-appshellbranding-logo

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#4818

Maintainer ruling, 2026-08-19, over the 27-card objectui decision-inbox review (comment 5339695386), verbatim: 「全部接受」 — option 1, remove. Option 2 (build a real branding context) was rejected as a permanent provider obligation with zero demand.

What was removed

AppShellBranding.logo was declared but never read.

  • useAppShellBranding (packages/layout/src/AppShell.tsx) applies only primaryColor, accentColor, favicon and title; its effect dependency array does not list logo at all.
  • AppShell installs no context provider, so the key's doc comment — "Logo URL — passed to sidebar/navbar via context" — named a mechanism that does not exist in the code. That comment is deleted with the key.

Six deleted lines, no additions, across four files plus a changeset.

Three feed lines, not one

The card named one feeder. There are three, and each one was handing the key a real value that was silently discarded:

Feed lineNamed by
apps/console/src/hooks/useBranding.ts:27logo: app.branding.logothe card
packages/layout/src/AppSchemaRenderer.tsx:582logo: schema.logothe dispatch's correction
packages/app-shell/src/layout/ConsoleLayout.tsx:174logo: activeApp.branding.logonobody

The third is the only reason this diff reaches packages/app-shell, which is outside the file surface the card and the dispatch drew. It is not optional: deleting the key makes that line a hard tsc error (evidence below), so leaving it would ship a red typecheck. It is the same defect class, the same mechanical one-line deletion as its two siblings, in a file no in-flight worktree or open PR touches, and it adds no new gate. apps/console/src/hooks/useBranding.ts also loses the matching logo?: string from its local AppBranding interface — that hook has zero callers today.

The premise check the dispatch asked for — measured, and it holds

The dispatch flagged one thing to verify rather than assume: AppSchemaRenderer forwarded schema.logo, a top-level app-schema key, while AppSidebar.tsx:194 reads activeApp?.branding?.logo, a nested one — so was the forward actually dead?

Measured on origin/mainbdf8cf76e: they are not the same key and not the same place — but that turns out not to matter, because neither logo render site goes through AppShellBranding at all. Both are untouched by this PR:

  • packages/layout/src/AppSchemaRenderer.tsx:385resolveIcon(schema.logo) — and :397-399, an img whose src is schema.logo, in the default sidebar header. This renders the top-level key directly, in the very same file that built the branding object. The forward at :582 was a second, parallel, dead route for a value the file was already rendering itself.
  • packages/app-shell/src/layout/AppSidebar.tsx:194activeApp?.branding?.logo, read directly off the app schema.

So the ruling's premise — "the logo already renders correctly today via the real path" — is true for both halves. The roll-back clause does not trigger.

Reverse verification

Stated per leg, because a deletion PR is exactly the shape that passes vacuously. tsc has a build artifact between the edit and the result for the two cross-package legs: the root tsconfig.json has no paths entry for @object-ui/layout, so consumers resolve it through node_modules to packages/layout/dist/AppShell.d.ts. Every leg below rebuilt that artifact first and proved the marker's presence or absence in it. Vitest is the opposite: vitest.config.mts:263 aliases @object-ui/layout to packages/layout/src, so no artifact sits between the edit and the tests.

Leg 1 — baseline, logo present in the built .d.ts. After building the dependency closure, packages/layout/dist/AppShell.d.ts:14 carried logo?: string;. All three consumer packages type-checked clean, i.e. writing logo compiled:

packages/layout type-check: Done
packages/app-shell type-check: Done
apps/console type-check: Done
EXIT=0

Leg 2 — key deleted, feed lines still in place; rebuild proved the marker gone (grep -c logo packages/layout/dist/AppShell.d.ts0). Each of the three consumers then failed, naming exactly one site:

packages/layout src/AppSchemaRenderer.tsx(582,5): error TS2353: Object literal may only
specify known properties, and 'logo' does not exist in type 'AppShellBranding'.
packages/app-shell src/layout/ConsoleLayout.tsx(174,15): error TS2322: ... Object literal may
only specify known properties, and 'logo' does not exist in type 'AppShellBranding'.
apps/console src/hooks/useBranding.ts(27,11): error TS2345: ... Object literal may only
specify known properties, and 'logo' does not exist in type 'AppShellBranding'.

That is the answer to "show that a consumer writing logo is now a compile error" — demonstrated by three real consumers, two of them resolving through the published .d.ts exactly as an external consumer would.

Leg 3 — feed lines deleted, artifacts rebuilt, marker re-confirmed absent. All three green again (EXIT=0).

Nothing rendering-visible changed. The removed key had no reader: no branch of useAppShellBranding touched it, and AppShell exposes no context for anything downstream to read it from. The two live render sites listed above still sit at the same lines.

Tests

Run from the repo root with path filters, never pnpm --filter pkg test — 17 packages here own a standalone vitest.config.ts that does not re-export the root config, so a package-scoped run executes a different config than CI.

pnpm exec vitest run packages/layout/ apps/console/ --maxWorkers=2
Test Files 76 passed (76)
Tests 874 passed (874)
pnpm exec vitest run packages/app-shell/src/layout/ packages/app-shell/src/console/ \
packages/app-shell/src/runtime-config.test.ts packages/app-shell/src/hooks/ --maxWorkers=2
Test Files 110 passed (110)
Tests 835 passed (835)

186 files, 1709 tests, zero failures. The second command's paths cover every packages/app-shell test that mentions ConsoleLayout, AppShellBranding or branding, plus the AppSidebar suites that guard the real logo path. The remainder of that package's 456 files is left to CI, which runs the whole farm once anyway.

Gates

Union re-run after the final commit, at 49dee42ad:

check-changeset-presence 4 source file(s) of 3 released package(s) changed, 1 changeset declared
check:changeset (fixed) All workspace packages are in the changeset fixed group
check:changeset (no-major) No changeset declares a `major` bump
check:control-bytes OK (4757 tracked text files)
check:doc-types Every documented component type is registered
check:doc-snippets 87 of 87 blocks judged, 0 failed — compiled against the BUILT types
check:phantom-deps Every in-scope import is declared by the package that publishes it
check:self-import No package names itself inside its own src/
lint 0 errors (201 pre-existing warnings, unchanged from main)

check:doc-snippets is the load-bearing one for a published-type deletion: it compiles documentation snippets against the built types and found no snippet writing logo on an AppShellBranding literal.

Docs

Versioning

minor for @object-ui/layout, @object-ui/app-shell and @object-ui/console — never major. Maintainer, 2026-08-19, verbatim: 「objectui ui 的 major 是要跟着 objectstack 走的,不可以自己发 major」. The changeset body names the removed published optional key and the real replacement path.


Generated by Claude Code

…4818)
`AppShellBranding.logo` was declared but never read. `useAppShellBranding`
applies only `primaryColor` / `accentColor` / `favicon` / `title` — its effect
dependency array does not even list `logo` — and `AppShell` installs no context
provider, so the key's doc comment ("Logo URL — passed to sidebar/navbar via
context") named a mechanism that does not exist in the code.
Three call sites were feeding the key a value that was silently discarded; all
three go with it:
- packages/layout/src/AppSchemaRenderer.tsx logo: schema.logo
- packages/app-shell/src/layout/ConsoleLayout.tsx logo: activeApp.branding.logo
- apps/console/src/hooks/useBranding.ts logo: app.branding.logo
The card named only the third; the first fails loud under tsc, and the second
was unnamed anywhere and is the reason this diff reaches packages/app-shell.
Nothing rendering-visible changes. The two real logo paths never went through
AppShellBranding and are untouched: AppSchemaRenderer renders the app schema's
top-level `logo` directly in its default sidebar header, and AppSidebar renders
the app schema's nested `branding.logo` directly.
Ruling: maintainer, 2026-08-19, over the objectui decision-inbox review —
option 1, remove. Building a real branding context (option 2) was rejected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)25.3 KB350 KB
Entry fileindex-ChU24_Pk.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.83KB3.70KB
app-shell (runtime-config.js)7.42KB2.32KB
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.33KB7.05KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.79KB
auth (createAuthenticatedFetch.js)6.34KB2.43KB
auth (index.js)2.71KB1.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.88KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.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.53KB113.13KB
core (index.js)4.11KB1.62KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)159.80KB44.34KB
fields (index.js)237.07KB59.46KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.42KB1.39KB
i18n (pickLocalized.js)3.69KB1.73KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)30.51KB7.57KB
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.74KB
mobile (index.js)1.50KB0.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.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.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.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
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.75KB18.37KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)128.07KB32.77KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)241.46KB60.56KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)124.19KB30.20KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)197.30KB53.06KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.66KB27.13KB
plugin-map (index.js)20.08KB6.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.52KB20.67KB
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.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)36.10KB12.26KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.33KB0.69KB
react (schema-input.js)1.45KB0.83KB
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-support-ai
os-support-ai marked this pull request as ready for review August 20, 2026 01:53
@os-support-ai
os-support-ai added this pull request to the merge queueAug 20, 2026
Merged via the queue into main with commit 86f633fAug 20, 2026
22 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-4818-appshellbranding-logo branch August 20, 2026 01:54
os-sales pushed a commit that referenced this pull request Aug 22, 2026
`apps/console/src/hooks/useBranding.ts` was a `@deprecated` thin wrapper around
`useAppShellBranding`, with no caller anywhere in the repo. The migration its own
deprecation note asked for had already happened: `ConsoleLayout` passes `branding`
straight to `AppShell`, and nothing was left behind to call the wrapper.
It was not free to keep. PR #5366 had to edit this file twice — the feed line and
its local `AppBranding` interface — purely to keep a file nobody calls compiling.
The hook was the only file in the console's hooks directory, so the directory goes
with it. `skills/objectui/guides/console-development.md` stated both coordinates in
backtick code spans, which `scripts/check-skills-paths.mjs` resolves against disk;
both are updated, and the caveat about the first row's differing prefix is dropped
because every remaining hook now lives in `@object-ui/app-shell`.
Fixes#5368
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding: AppShellBranding.logo 无任何读取方,注释「passed to sidebar/navbar via context」是假的(AppShell 不提供该 context)

2 participants

@os-support-ai@claude