Skip to content

refactor(electron): extract main process boundaries - #7532

Merged
chenmingwei23 merged 1 commit into
mainfrom
refactor/electron-main-boundaries
Sep 2, 2026
Merged

refactor(electron): extract main process boundaries#7532
chenmingwei23 merged 1 commit into
mainfrom
refactor/electron-main-boundaries

Conversation

@bolichen97

@bolichen97 bolichen97 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Problem / Motivation

website/electron/main.js had grown to 4,246 lines and jointly owned gateway supervision, IPC registration, window/security lifecycle, browser control, and recovery. That concentration made lifecycle ordering and cleanup ownership difficult to review or test safely.

Why it matters

The desktop shell coordinates child-process ownership, single-instance behavior, hardened Electron sessions, navigation policy, updater handoff, and cross-platform window state. Keeping those responsibilities in one module made an otherwise local change more likely to disturb an unrelated security, startup, or shutdown invariant.

What changed (motivation → approach → change)

This is an intended behavior-preserving boundary extraction. main.js is now a 431-line composition root that retains application-level ordering, while three dependency-injected sibling modules own cohesive runtime state:

  • gateway-supervisor.js owns gateway discovery, start/stop, liveness, recovery, token flow, child-process cleanup, and updater handoff.
  • window-lifecycle.js owns dashboard/tray/browser windows, browser-control ownership, session and navigation hardening, diagnostics, and window cleanup.
  • ipc-registrar.js owns shell, updater, hotkey, memory-sampling, and WSL-detection IPC registration.

The extraction keeps existing IPC channel names and payload shapes, single-instance behavior, app/window/process lifecycle order, partition/session hardening, external-navigation policy, browser-control sender ownership, and platform-specific branches. Timing and security WHY comments stay with their owning boundaries; obsolete historical/code-restatement comments were removed. Direct Electron tests now exercise the injected modules and their composition seams, and the owning desktop/i18n/update docs describe the new ownership boundary.

website/electron/package.json changes only electron-builder's existing files allowlist so the three new sibling modules are packaged. No dependency, script, version, or lockfile changed.

The base sync carries the chat copy-link menu wiring that landed on main while this branch was open: the dashboard's attachContextMenu call now receives { getAppOrigin: () => windowBackendUrl } at its new home in window-lifecycle.js, and the embedded browser panel still passes no origin. A source contract in window-lifecycle.test.js locks that split so a later move cannot silently drop either half.

Tests

  • npm run test:electron: the 19 electron test files this PR adds or changes, plus context-menu.test.js, pass together — 225 tests, 0 failed. The remaining reds in a full local run (packaging, build-config-schema, store-rename-migration, auto-update*, petOverlays, and the gateway-stop hang) reproduce identically on origin/main with the same missing-module / ENOENT causes, so they are host setup, not this diff.
  • Direct extraction/WSL group: 120 passed, including sender-origin/window ownership, primary-port owner, lifecycle cleanup, and registration-order contracts.
  • Windows x64 unpacked package smoke: electron-builder passed; the 1,023-entry ASAR contains main.js, all three extracted modules, and wsl-detection.js.
  • npx tsc -b, production Vite build, analyze build, and bundle-size gate passed (6,915 modules; 738 chunks within budget).
  • i18n 19-check runner, phantom-class 28-probe self-test plus real gate, i18n render gate, jscpd, vendor manifest, Python static/security/docs gates, and the latest-base PR quality contract test passed.
  • Full backend floor: 72,702 passed, 3,183 skipped, 5 xfailed, 37 failed. Thirty failures require unavailable Windows symlink privilege; the other seven are in unchanged browser-recording/IRQ/PPTX/ratchet/performance/snapshot tests. None of the 37 failing test files intersects this PR's changed paths.
  • Full frontend floor before the final base sync: 27,243 passed, 1 expected failure, 4 skipped, 2 failed on timeouts in unchanged renderer tests (DevFleetPageCoverage and ImeEnterClaimRatchet); one unchanged MarkdownRenderer worker also timed out during termination. Because Vitest exited red, it did not emit the coverage report. After syncing the latest base, a targeted run of both timeout files plus MarkdownRenderer passed all 202 tests without the worker warning. website/src is identical to origin/main in this branch.
  • Frontend ESLint (npx eslint src/ --max-warnings 603) is inherited unchanged: website/src is byte-identical to origin/main on this branch, so this diff can neither add nor remove a warning. website/electron/** has no eslint rules configured, so lint over the extracted modules only proves they parse; node --test is their real coverage. The default Python 3.13 launcher also lacks some gate dependencies, so equivalent installed Python 3.12 checks were used where noted; the docs self-test's symlink probe cannot run without the Windows symlink privilege, while the real docs lint passed.

Manual verification

  • Built and inspected a real Windows x64 unpacked Electron package, overriding only the release-only bundled backend resource; the generated smoke directory was removed afterward.
  • No rendered UI changed, so screenshots are not applicable.
  • Still best verified by release coverage on macOS/Linux and by packaged updater/service-manager paths: real BaseWindow/tray/fullscreen/activate timing, POSIX ownership probes, and updater failure rollback cannot be fully exercised on this Windows host.

Related Issues

no linked issue: this is a self-directed maintainability refactor of the Electron main process, not a fix for a reported defect.

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title (feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

@bolichen97
bolichen97 requested a review from a team September 1, 2026 06:21
@bolichen97
bolichen97 requested a review from a team as a code owner September 1, 2026 06:21
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of 3ee74e349f58e1783bb1533b50968b92454c7a66 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 3ee74e3

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 3ee74e349f58e1783bb1533b50968b92454c7a66: <one-sentence reason>

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

UX-level review of 3ee74e349f58e1783bb1533b50968b92454c7a66 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All user-facing surfaces (dialogs, tray menu, status strings, permission prompts, update notification) survived the extraction byte-for-byte — only rewrapped across lines — and website/src is untouched. Nothing a user experiences changed. Emitting the review.

UX-Verdict: PASS

Pure main-process boundary extraction: every dialog, tray label, status string, and permission prompt moves verbatim; no rendered surface or flow changes.

[UX-REVIEWED] 3ee74e3

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — 🟡 CONCERNS

Premise-level review of 3ee74e349f58e1783bb1533b50968b92454c7a66 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All mechanical checks are done: IPC channel sets, env vars, store keys, and timing values are identical between the base main.js and the extracted modules; the packaging allowlist and doc edits are exactly what the extraction requires. The one thing the description doesn't mention: the new modules ship defensive fallback branches for façade shapes that no caller has.

First-Principles-Verdict: CONCERNS

The extraction is real and earns its place, but it ships fallback branches for callers that do not exist — a "transitional alias" with zero providers.

What this change ships

Intent: make the 4,246-line Electron main process reviewable and directly testable by splitting it into three injected modules. ADDITION (structure-only move; no fix claimed).

  1. Gateway start/stop/recovery/updater handoff moves to gateway-supervisor.js — justified
  2. Window/tray/session-hardening/browser-control moves to window-lifecycle.js — justified
  3. Shell/updater/hotkey/WSL IPC registration moves to ipc-registrar.js — justified
  4. main.js becomes a 431-line composition root — justified
  5. Packaged app ships the three new modules (files allowlist) — justified
  6. Desktop/i18n/update docs re-point stale main.js line refs — justified (same-commit doc invariant)
  7. Three direct test suites, 16 adapted — justified
  8. Copy-link context-menu origin wiring re-homed from base sync — declared, rides along
  9. Fallback branches for façade members every caller supplies — undeclared, zero consumers
  10. Façade exports only tests call (~13 members) — undeclared surface

Behavior preservation verified mechanically: 37 IPC channels, all store keys, env vars, and the 250/1500/400ms timing values match the base byte-for-byte; website/src is untouched.

Watch

createWindowLifecycle returns ~13 members no production code calls (openNewSessionWindow, promptRemoteHost, refreshToken, getTray, positionTrafficLights, persistMainWindowState, focusedDashboardWebContents, …) — counted against main.js + ipc-registrar.js, the only two consumers. They exist for tests; each is façade surface a later caller can bind to without review.

Subtractions

  • Delete the "Transitional alias" branch at ipc-registrar.js:84-89: the flat name windows.configureSessionSecurity is provided nowhere (grep: 1 definition, 1 façade entry as security.configureSession, this one dead call) — call windows.security.configureSession() unconditionally.
  • Delete the getSummonWindow typeof-fallback at ipc-registrar.js:59-63 — the façade returns it unconditionally (window-lifecycle.js:1858).
  • Drop the dead defaults for values the single composition root always passes — home || resolveHome() (gateway-supervisor.js:136), backendUrl default (:106), and the typeof-guards on log/logPath/getMainWindow/isQuitting/requestQuit (:140-151); 1 production caller (main.js:188-206) supplies every one, and a silent no-op fallback masks a mis-wiring the guard exists to survive.

[FIRST-PRINCIPLES-REVIEWED] 3ee74e3

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 3ee74e349f58e1783bb1533b50968b92454c7a66 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

The extraction maps cleanly: security hardening hooks, quit ordering, and IPC surfaces carry over 1:1, the base's module-load runLocalGateway snapshot semantics are preserved, packaging allowlist and owning docs are updated in the same change, and each new module has direct seam tests. The residual macOS/Linux packaged-path risk is already named honestly in the PR itself.

Design-Verdict: PASS

A real maintainability harm, fixed at the root with a proportionate, behavior-preserving decomposition — DI seams tested, docs and packaging updated in-commit.

[DESIGN-REVIEWED] 3ee74e3

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 3ee74e349f58e1783bb1533b50968b92454c7a66 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 3ee74e3

Verdict parsed from the review's SHA-scoped output markers for commit 3ee74e349f58e1783bb1533b50968b92454c7a66.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 3ee74e349f58e1783bb1533b50968b92454c7a66: <one-sentence reason>

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 1, 2026
@bolichen97
bolichen97 force-pushed the refactor/electron-main-boundaries branch from 7dd4c2e to 9c8ef4e Compare September 1, 2026 06:57
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 1, 2026
@bolichen97
bolichen97 force-pushed the refactor/electron-main-boundaries branch from 9c8ef4e to cc02b33 Compare September 1, 2026 23:28
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: checking Automated validation is still running labels Sep 1, 2026
@bolichen97
bolichen97 force-pushed the refactor/electron-main-boundaries branch from cc02b33 to 3ee74e3 Compare September 2, 2026 01:44
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: passed Eligible automated validation passed for the current revision and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 2, 2026

@chenmingwei23 chenmingwei23 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: PR Readiness passed, all review lanes green.

@chenmingwei23
chenmingwei23 merged commit d85fbed into main Sep 2, 2026
70 checks passed
@chenmingwei23
chenmingwei23 deleted the refactor/electron-main-boundaries branch September 2, 2026 03:57
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Sep 2, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator Author

Open PR relationship audit

This is a consolidated, point-in-time code-level audit note. It compares complete merge-base diffs and current/merged code; it does not treat a shared topic as duplication or partial coverage as completion.

Relationship findings

  • PR #7196 is OVERLAPPING relative to this PR. The goals differ or the implementations can complement each other; this is not a duplicate claim. Recommended action for PR #7196: REBASE. A merged refactor moved this PR's host code out of main.js into window-lifecycle.js, so the change must be re-applied there and its source-pinning test updated. Independent of the PR #5738 stack. Files: website/electron/main.js.

No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants