Skip to content

refactor(desktop): move App Update controller below AppShell - #4498

Open
chihumyum wants to merge 1 commit into
apache:mainfrom
chihumyum:refactor/app-update-feature-scope
Open

refactor(desktop): move App Update controller below AppShell#4498
chihumyum wants to merge 1 commit into
apache:mainfrom
chihumyum:refactor/app-update-feature-scope

Conversation

@chihumyum

@chihumyum chihumyum commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Move the renderer-owned App Update lifecycle out of AppShell into a feature slice, with AppUpdateProvider as the sole production owner of useAppUpdateController.

  • compose update capabilities through a typed Desktop adapter and feature service port; AppShell now only mounts the Provider
  • project update state independently to About and Sidebar Footer, so progress events no longer invalidate navigation or the shell
  • keep the shared update contract type-only while preserving subscription-before-snapshot ordering, stale-result fences, and single-flight check/install behavior
  • add AST-backed boundary tests that pin the controller, Provider, adapter, and leaf readers, while rejecting raw or computed bridge access, internal imports, aliases, namespaces, re-exports, export-all, and dynamic imports

No user-visible copy, update protocol, or install behavior is intended to change.

Refs #4582 (supersedes #3439)

Performance evidence

Measured in Electron 43.4.1 with a production React bundle, the same renderer PID, and alternating legacy/scoped runs:

Controlled downloading-status workload AppShell owner Feature owner Change
React commits per push 1 1 unchanged
Rendered fibers per push 512 1 -99.8%
Pure renderer/controller busy JS 0.1329 ms/push 0.0068 ms/push -94.9%
Full IPC -> preload -> adapter -> Provider busy JS 0.2111 ms/push 0.0696 ms/push -67.0%

The structural run used 8 rounds x 40 pushes, the pure renderer run 9 alternating rounds x 1,000 pushes, and the full propagation run 7 alternating rounds x 200 pushes. The full path used a real BrowserWindow, Electron IPC, the production preload bundle, Desktop adapter, and App Update Provider; only the main status producer was a fixture.

These measurements cover controlled renderer update propagation. They do not claim faster updater downloads or installs, lower main-process/network/disk cost, total wall/FPS improvement, or an exact production AppShell fiber count.

Verification

  • npm run rebuild, npm run typecheck, npm run lint, and npm run format:check
  • App Update focused suites: 22/22
  • Desktop and UI full compiled test suites
  • renderer architecture fixtures: 61/61; AppShell hook gate: 42 hooks / 77 call sites
  • Astryx inventory: 239 files / 1 declared exclusion
  • Knip for apps/desktop and packages/ui, ASF headers, stale-dist, and git diff --check
  • the default full-workspace sweep's only local non-green signal was Node's experimental SQLite warning from a managed Storage child; with NODE_NO_WARNINGS=1, Storage passed 1,077 tests with 8 skipped
  • node scripts/desktop-real-window-smoke.mjs --programmatic-only --diagnostic-wait-ms 20000 passed against the built renderer: visible 1280x840 movable/resizable window, renderer ready, appFrame mounted, Search focused, dock visible, and no ErrorBoundary
  • manual real-window inspection after closing Search showed sidebar, tasks, conversation, and composer rendering normally without a crash or ErrorBoundary
  • built Settings Storybook play clicked "检查更新", observed "已是最新版本。", and reported no page or console errors

The real-window smoke used a source-built Electron app, not a packaged or signed installer; packaged updater download/install remains outside this PR's evidence.

Review focus

Please review the ownership guard and the two independent projections together: the feature should retain the only update subscription and bridge capability, while About and Sidebar Footer receive only the state needed at their render boundaries.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex contributed substantive architecture design, implementation, tests, performance measurement, and verification. The human contributor reviewed the work and chose to submit it.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@github-actions github-actions Bot added the effort/XL Over 1000 readable lines label Sep 1, 2026
@chihumyum
chihumyum force-pushed the refactor/app-update-feature-scope branch from 628a5ec to d5cd6e9 Compare September 2, 2026 16:14
@chihumyum

Copy link
Copy Markdown
Contributor Author

@Astro-Han could you please review exact head d5cd6e9ab2e8b47f1b9e9eddd289c1302b658799?

I rebased it onto main@b714a392192961fef3d89d4358fb0a0858252804. The conflict resolution keeps the new Session Settings / Runtime Host composition alongside the App Update provider and regenerates the renderer architecture and Astryx ledgers from the combined source.

Exact-head local verification passes: rebuild; renderer architecture 71/71 plus the base ratchet; App Update 22/22; Desktop 1,982/1,982; UI 313/313; typecheck, lint, format, Desktop/UI Knip, ASF headers, AppShell hook scope, Astryx inventory; and the real Electron window smoke. The new hosted CI and Windows package checks are currently queued.

@chihumyum

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (c86da40d7, which includes #4571's About page rebuild). Exact head: 076fb612f579e0ed890b082b8e488bf134a9a793.

How the two real conflicts were resolved:

  • about-settings-page.tsx is refactor(desktop): rebuild the About page as labeled settings groups #4571's page verbatim; only update ownership changed. The status row is now AboutUpdateRow, rendered through AppUpdateAboutProjectionConsumer, and the page no longer calls window.maka.app.*. The dev-build decision (no status line) stays on the page as refactor(desktop): rebuild the About page as labeled settings groups #4571 put it.
  • aboutUpdateStatusDetail follows main's two-argument signature (no isDevBuild) and lives in the feature model; aboutChannelFacts stays in settings/about-update-status.ts because it is About copy, not update state. about-update-status.test.ts imports each from its owner.
  • Stories: About is back to main's dev-checkout form (its e2e asserts no update button); the previous play moved to a new AboutCheckForUpdates story on a packaged release. The story-side services read window.maka.app per call so the channel stories' updateStatus overrides reach the provider.
  • renderer-architecture.json and the Astryx inventory were regenerated.

Local verification on this head with Node 24: desktop test:dist 1988/1988, @maka/ui 313/313, typecheck (four projects), lint, format, check:renderer-architecture --base upstream/main, check:app-shell-hooks (42 hooks / 75 call sites), Astryx inventory, Knip (desktop, ui), ASF headers, git diff --check, and build:renderer — all green.

Automated update from Claude Code on behalf of the PR author.

@chihumyum
chihumyum force-pushed the refactor/app-update-feature-scope branch from 076fb61 to 750ee05 Compare September 2, 2026 18:40
@chihumyum

Copy link
Copy Markdown
Contributor Author

Rebased again onto current main (ad18da42c, #4455). One real conflict, in packages/ui/stories/session-rail-harness.tsx: #4455 added the railSelection prop and forwards it to SessionRailProvider, this PR wraps that provider in SidebarUpdateProjectionProvider; the merge keeps both. The Astryx inventory was regenerated. Exact head: 750ee054c66babfe2107279a9bb3d979bbbaaf31.

Same local verification on this head with Node 24: desktop test:dist, @maka/ui test:dist, typecheck (four projects), lint, format, check:renderer-architecture --base upstream/main, check:app-shell-hooks, Astryx inventory, Knip (desktop, ui), ASF headers, git diff --check, build:renderer — all green.

Automated update from Claude Code on behalf of the PR author.

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

Labels

effort/XL Over 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant