Module orphan_reconcile

Module orphan_reconcile 

Source
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§

OrphanReconcileTask
ReconcilePlan 🔒
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§

CloseAction 🔒
What the planner decided to do with a single label.
HwndStatus 🔒
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 + the host() 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 to plan_reconcile.
drive_close_browser 🔒
Execute a CloseBrowser action. Already on UI thread. host.close_browser(force=1) works regardless of HWND state and triggers the host’s on_before_close callback chain (which dispatches UnregisterBrowser and drives Stage-2 quit naturally). Returns true iff 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 UnregisterBrowser action. Hostless candidates can’t be close_browser’d (no BrowserHost to call it on), so we clean state.browsers ourselves. Caller drives quit_message_loop after the loop if any unregister fired.
plan_reconcile 🔒
Pure planning function. The orchestrator HWND-probes every non-pane top-level browser in state.browsers and 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.