Expand description
Host-side orphan-instance reconciliation. Spec:
docs/specs/SPEC_HOST_ORPHAN_RECONCILIATION_2026_05_05.md.
When the launcher detects that the last user-visible window
has closed but the host is still alive, it emits
Event::HostShouldQuit. The host’s handler invokes
reconcile_and_drain here, which closes any orphan
window-pool-* browsers (promoted out of the warm pool, but
the launcher mirror has dropped them — typically because their
HWND was destroyed without the host’s on_before_close running).
Each close funnels back through client::on_before_close,
whose Stage 2 hook fires quit_message_loop() once
browser_list empties — so the reconciler doesn’t drive
UI-thread shutdown directly.
Threading: CEF Browser/BrowserHost methods (host(),
window_handle(), close_browser()) MUST run on the UI
thread per CEF docs. The IPC reader thread that delivers
HostShouldQuit does only state-snapshot + classification
work, then cef::post_tasks the UI-thread closure.
Structs§
- Orphan
Reconcile Task - Reconcile
Plan 🔒 - Output of the pure planning step. The orchestrator executes this against real CEF state. Kept separate so tests can verify decisions without standing up a CEF runtime.
Enums§
- Close
Action 🔒 - What the planner decided to do with a single label.
- Hwnd
Status 🔒 - HWND liveness state of a candidate browser. Inputs to the
planner; computed in production from real CEF/Win32 calls in
hwnd_is_dead_or_missing+ thehost()check, supplied directly in tests.
Functions§
- classify_
hwnd 🔒 - Map a Browser to its
HwndStatus. Calls CEF + Win32; only safe from the UI thread. Used by the orchestrator to build the input toplan_reconcile. - drive_
close_ 🔒browser - Execute a
CloseBrowseraction. Already on UI thread.host.close_browser(force=1)works regardless of HWND state and triggers the host’son_before_closecallback chain (which dispatchesUnregisterBrowserand drives Stage-2 quit naturally). Returnstrueiff the browser’s host had vanished by execute time and the orchestrator should treat this as a late hostless transition (relevant for the Stage-2 quit drive — same reasoning as the planner’s Hostless bucket). - drive_
unregister 🔒 - Execute an
UnregisterBrowseraction. Hostless candidates can’t beclose_browser’d (noBrowserHostto call it on), so we cleanstate.browsersourselves. Caller drivesquit_message_loopafter the loop if any unregister fired. - plan_
reconcile 🔒 - Pure planning function. The orchestrator HWND-probes every
non-pane top-level browser in
state.browsersand feeds that map here. - reconcile_
and_ drain - IPC-thread entry point. Posts a UI-thread task that does all
state-snapshot + classification + close work. The IPC thread no
longer pre-classifies candidates — between IPC and UI execution,
labels can move between
pool.unpromoted/pool.queue/ promoted-into-shadow. Re-snapshotting on the UI thread avoids stale classification. - ui_
thread_ 🔒reconcile - UI-thread body. CEF Browser methods are safe here.