Skip to content

desktop: classify expected sidecar shutdowns - #1776

Merged
RhysSullivan merged 4 commits into
mainfrom
fix/desktop-sidecar-shutdown-classification
Aug 28, 2026
Merged

desktop: classify expected sidecar shutdowns#1776
RhysSullivan merged 4 commits into
mainfrom
fix/desktop-sidecar-shutdown-classification

Conversation

@RhysSullivan

@RhysSullivan RhysSullivan commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Problem

When the local server (the desktop sidecar) is interrupted from outside the app — a group-wide Ctrl-C aimed at Electron, which reaches the child because it shares Electron's process group — the app treated it as a crash. Only a stop the app initiated itself counted as expected, so an ordinary shutdown filed a crash report and the window told the user one had been sent.

Two follow-on symptoms come from the same moment:

  • The renderer's lazy route chunks then fail to load (Failed to fetch dynamically imported module). Nothing listened for vite:preloadError, so the rejection went unhandled and the route was simply dead, with no explanation and a reported TypeError.
  • loadURL rejects with ERR_FAILED when its window is destroyed mid-navigation. That is a teardown race we cause, not a failure to reach the server, but it surfaced as an error.

Fix

  • A pure classifySidecarExit splits a post-boot exit into managed-stop / external-shutdown / crash. A shutdown signal (SIGINT/SIGTERM/SIGHUP, or the matching 129/130/143 exit codes) or a quit already in progress still shows the disconnected screen — the server really is gone — but reports nothing and does not claim a report was sent. Every other exit is reported exactly as before.
  • A vite:preloadError handler probes /api/health to tell a dead server from a stale chunk: reconnect surface and no report when the server is gone, one session-guarded reload when it answers, reported if that reload does not help.
  • loadURL aborts during teardown are classified and logged instead of becoming unhandled rejections.

Testing

No e2e scenario: neither behaviour is observable through the harness. The exit classification only changes what is reported and what the crash screen claims, and both are gated on a release-only build define that dev and e2e builds never have; vite:preloadError is dispatched only by Vite's production preload helper, and the targets whose server can be killed mid-run serve dev bundles where it never fires. So verification here is unit-level.

The tests cover the classifiers and the wiring around them, since a correct verdict acted on wrongly is the same bug:

  • A post-boot exit is driven through the real startSidecar, with only the process spawn and Electron's environment replaced. An outside interrupt is checked to leave the crash channel untouched and to tell the window nothing was sent; a genuine death still reports; a stop we asked for says nothing at all.
  • The environment the browser actually hands the preload-error responder is tested directly — health probe, single reconnect overlay, and the one-reload-per-session guard, including the blocked-storage case that must degrade to reporting rather than looping.
  • The crash screen is pinned not to claim a report was sent when none was.

The one link still uncovered is the single line in index.ts that passes the notice to the crash screen; that module boots the whole app at import, so covering it needs a full Electron harness for one assignment.

apps/desktop and packages/app suites, typecheck, lint and format pass. No signing, updater, or process-group changes here.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Cloudflare preview

Torn down — the PR is closed.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 27, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing c092bd4 Commit Preview URL

Branch Preview URL
Aug 28 2026, 02:54 AM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 27, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud c092bd4 Aug 28 2026, 02:56 AM

@pkg-pr-new

pkg-pr-new Bot commented Aug 27, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@1776

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@1776

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@1776

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@1776

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@1776

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@1776

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@1776

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@1776

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@1776

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@1776

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@1776

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@1776

executor

npm i https://pkg.pr.new/executor@1776

commit: c092bd4

The reconnect path reported a stale chunk through the global reportError
hook, which files it as an unhandled crash and drops the surface and action.
Route it through the renderer's handled-error reporter instead.
@RhysSullivan
RhysSullivan force-pushed the fix/desktop-sidecar-shutdown-classification branch from e10b725 to c092bd4 Compare August 28, 2026 02:52
@RhysSullivan
RhysSullivan marked this pull request as ready for review August 28, 2026 03:12
@RhysSullivan
RhysSullivan merged commit 03d23b9 into main Aug 28, 2026
79 of 80 checks passed
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.

1 participant