Repository navigation
Main-process exceptions no longer block quitting (D28): the check, the strip's fade timer, two test races - #11
Conversation
…blocked quitting (D28) Electron's default uncaughtException handler shows a modal error box that holds the main thread until someone dismisses it, so Orbit couldn't quit. Under Xvfb nobody dismisses it: e2e app.close() hung, then Playwright's worker teardown, which failed whole jobs (macOS CI on PR #7 and main, three local full runs). A user would have seen the box and an app that wouldn't quit. - src/main/index.ts: log "[orbit] uncaught exception:" and carry on. - tests/e2e/helpers.ts: app.close() fails a test whose main process logged one (takeUncaught() claims one thrown on purpose) and kills an Orbit that still hasn't quit 15 s after being asked, so one stuck quit can't hang the run. - core.spec.ts: [TB-22] a throw in a main-process timer is logged, Orbit quits and the session restores. Without the fix nothing is logged and the quit hangs until the harness kills it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… before the evaluate replies fromMini sends a command from the Mini Window's own page. mini.control's close can close that page before Playwright gets the evaluate's reply, which then fails with "Target page, context or browser has been closed" (MW-10, once in a full run). The helper now ignores that error only when the page really closed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… growing in A pane added a moment ago springs open from zero width (SV-26), so its first bounding box can be empty. The poll now retries instead of failing at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: bfd72d5f-77f3-436b-83d1-3b65c22c88a0) |
…de-out threw and blocked quitting (D28) The strip fades out for 120 ms before its view hides. When its window closed during the fade (as happens when Orbit quits right after a pane strip hid), the fade's timer still ran on a view whose page was gone: view.webContents was undefined, and reading isDestroyed() threw. Nothing caught that, and Electron's modal error box then held the main thread, so Orbit never quit. This is the exception behind the SV-03 hangs: 15 repeats of SV-03 with the D28 check logged it once. The window's closed handler now clears the strip's show, hide and fade timers, and every check of the strip's view also handles a view whose webContents is gone. Test: "[SV-12] a window that closes while its pane strip fades out closes cleanly (D28)". It fails without the fix (3/3: the TypeError above) and passes with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: 6a14680b-278f-4e9b-ac0e-001e3c849c28) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: 1a54cc4f-a258-4fdb-817e-425b102e50fe) |
…#11 review M1) checkQuit kept only the last 4,000 characters of stderr before it looked for the "[orbit] uncaught exception:" marker. An exception logged in one longer write (a big message, a cause chain, an AggregateError) lost its marker to the trim: the test passed and takeUncaught() returned ''. The scan now looks for the marker in the whole chunk first, keeps up to 4,000 characters from it, and otherwise carries only a marker-length tail so a marker split across two writes is still found. New TB-22 test: a main-process timer throws a 5,000-character message. It fails without the fix (takeUncaught() returns '') and passes with it, 3/3. core + split + smoke e2e: 62/62. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: 40bc7f91-adcb-4857-8fb9-37735711fe79) |
…Ubuntu 26 (Oct 19) GitHub's notice says `ubuntu-latest` becomes Ubuntu 26 from 2026-10-19. The e2e job installs xvfb, libgbm1 and libasound2t64 with apt, which is only known to work on 24.04, the image `ubuntu-latest` runs today. So nothing changes until that date; after it, the jobs stay on 24.04 until someone checks 26 on purpose. CI-only change (D18). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: f02846ec-ee67-4fa7-988b-19a1e1b95054) |
…cks apps that quit on their own, and samples a stuck main thread on macOS Follow-ups F1, F2 and F4 from PR #11's review (D28). - F1: Playwright does work of its own before it asks Orbit to quit (5 s after a failed test, measured by the reviewer), and the 15 s clock used to include it. In e2e mode main now logs "[orbit] quit requested" in before-quit; Orbit gets 15 s from that line, or 35 s from app.close() if the line never comes. The failure says which. - F2: an app that quits on its own (its last window closed) had no app.close() to check it. It is now remembered when it closes, and the next launchOrbit() checks it. - F4: macOS has no /proc, so a kill said "main thread: unknown". It now runs `sample <pid> 1` and reports the main thread's deepest frames, with the full sample's path. Not run on macOS yet; any error still falls back to "unknown". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…thing handled in main Electron only prints a warning for an unhandled rejection in the main process, so the D28 check never saw one. Main now logs them with the same marker as an uncaught exception, so the check fails the test that caused it. The new TB-22 test fails without the logging (received "") and passes with it. PR #11 review F3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: - Sidebar.tsx: the update banner and media's tray both sit above the Space switcher, the banner first. - rpc.ts: RendererView takes both 'pip' and 'onboarding'. - FEATURES.md: regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/ARCHITECTURE.md §9: main's E2E bullet (dead proxy, deferred evaluates, the quit check) with this branch's merge-gate bullet in place of the CI one. FEATURES.md regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Was stacked on PR #10 (base
lead/polish2), since both changetests/e2e/helpers.ts. #10 has merged, so the base ismainnow.What
[orbit] uncaught exception: …), and Orbit carries on (src/main/index.ts).tests/e2e/helpers.ts).app.close()now checks the quit:orbit.takeUncaught()claims one thrown on purpose;13a2494,src/main/split/strip.ts):view.webContentswasundefined, so readingisDestroyed()threwTypeError: Cannot read properties of undefined (reading 'isDestroyed');closedhandler clears the strip's show, hide and fade timers, and every check of the strip's view handles a view whose page is gone.docs/ARCHITECTURE.md§9 explains the check.5efc435):fromMinisends a command from the Mini Window's own page. A close can shut that page before Playwright gets the evaluate's reply ("Target page, context or browser has been closed"). The error is now ignored, but only when the page really closed.721fdc8, cherry-picked from the chrome lane's442766d): a pane added a moment ago grows in from zero width (SV-26), so it may have no box yet. The views-over-panes poll threw on that and failed at once; now it retries.Why
afterEach'sapp.close(), then "Worker teardown timeout of 60000ms exceeded". That fails the job even when the test passes on retry:mainatcc43e90(MW-14);app.quit()through the inspector, then waits for the process to exit. No Orbit handler cancels a quit.setTimeoutthat throws makesapp.close()hang, with the main thread parked indo_poll(the box's nested loop). A rejected promise doesn't.Tests
[TB-22] an exception nothing caught in the main process is logged; Orbit still quits and restores (D28)(core.spec.ts). It throws in a main-process timer, checks the log, quits and relaunches with the same profile.still running (main thread: do_poll.constprop.0).[SV-12] a window that closes while its pane strip fades out closes cleanly (D28)(split.spec.ts). It opens a second window so Orbit keeps running, starts the strip's fade, closes the strip's window, and waits past the fade.TypeErrorabove. With the fix, it and the three other strip tests passed 20/20 (5 runs each).before-quitprevented) is killed at 15 s, and its test fails;4fe445a(1440×900, 1 worker, 11.9 min): 216 passed, 2 failed. The failures were MW-10 and SV-17, the two test races above. No test logged an uncaught exception, and no quit needed the kill. After the fixes, MW-10 and SV-17 passed 12/12 (6 runs each).13a2494(1440×900, 1 worker, 9.4 min): 219/219 passed. No exception logged and no kill.npm run typecheckandnpm run lintexit 0; unit tests 252/252.Review
reviews/lead-quit.mdin the Orca context, at13a2494): APPROVE WITH FIXES, 1 must-fix and 6 follow-ups.504872a(test harness only): the quit check missed an exception whose log ran past about 4,000 characters, because it trimmed stderr before looking for the marker. It now looks first and keeps only a marker-length tail otherwise. A new TB-22 test throws a 5,000-character message: it fails without the fix (takeUncaught()returned'') and passes with it, 3/3. core + split + smoke e2e: 62/62.7eaec40merges PR Lead polish 2: full-split drop target, Favorite splits past 12, e2e evaluate race #10's two review fixes into this branch; the reviewer checked them atd2e4b8d.d19b9da, CI only (D18): the two Linux jobs are pinned toubuntu-24.04. GitHub movesubuntu-latestto Ubuntu 26 from 2026-10-19, and the e2e job's apt packages are only known to work on 24.04, the imageubuntu-latestruns today.sampleof the stuck process on macOS before the kill;Local check (merge gate, D42)
GitHub Actions is off for cost, so this local check is the merge gate. On
d19b9da, in this PR's worktree (Linux, Xvfb, one worker):split.spec.ts:115): the pane's view reached 527 px against more than 533 while the machine was loaded. Rerun alone, it passed (4.7 s), as in earlier runs. This PR's only split change is the pane strip's timers (strip.ts), not the divider drag. SV-03, whose quit hung in PR Lead polish 2: full-split drop target, Favorite splits past 12, e2e evaluate race #10's run without this fix, passed.[orbit] uncaught exception:, and no quit needed the kill. Since this head contains PR Lead polish 2: full-split drop target, Favorite splits past 12, e2e evaluate race #10, this run is also Lead polish 2: full-split drop target, Favorite splits past 12, e2e evaluate race #10's check.main): the fix is Electron's error box, which is the same code on macOS, but no macOS run has confirmed them gone.d19b9dapins the Linux CI jobs toubuntu-24.04. The workflow is disabled now (D42), so that change is inert; it keeps the file right if the workflow is ever turned back on.🤖 Generated with Claude Code
Note
Medium Risk
Changes main-process error handling and split strip lifecycle timers; behavior on real bugs shifts from a blocking dialog to continued execution, which is intentional but affects how failures surface in production.
Overview
Uncaught main-process exceptions no longer block quit: Electron’s modal is replaced by logging
[orbit] uncaught exception:insrc/main/index.ts(D28).Split pane strip (
strip.ts) clears show/hide/fade timers when the window closes and uses alive()guard so fade timers don’t touch destroyed views—the failure mode that hungapp.close()in E2E.E2E harness (
helpers.ts):launchOrbitwrapsapp.close()to fail on any uncaught main exception (withtakeUncaught()for intentional throws), kill the app after 15s if quit stalls, and detect the marker even when stderr writes exceed ~4k chars. New TB-22 / SV-12 tests cover logging, quit/restore, long logs, and strip fade + window close. MW-10 ignores evaluate errors when the Mini Window page closes first; SV-17 polling tolerates panes still growing in (SV-26).CI pins Linux jobs to
ubuntu-24.04instead ofubuntu-latest; ARCHITECTURE.md §9 documents the harness behavior.Reviewed by Cursor Bugbot for commit d19b9da. Bugbot is set up for automated code reviews on this repo. Configure here.