Goal
Make tab management (tab new <url>, switch, close, list) work on the Chromium (CEF) engine. Today these return cefUnsupportedError and Tab is hardcoded to WKWebViewRenderer.
Why deferred
An adversarial design review (Claude + Codex, both NO-GO) on a per-tab-engine / multi-CEF-browser design found it multiplies the documented navigate-while-hidden CrBrowserMain crash. The single-CEF path only survives today because ServerState.switchRenderer carefully sequences deactivate → migrate → wait-for-attachment → activate (+ surface refresh). The tab addTab/activateTab path has none of that choreography. Additional verified blockers:
CEFRenderer has no public closeBrowser(); closing a CEF tab risks teardown-while-attached (RendererContainerView never removes CEF views).
- New-tab-then-immediately-active = navigate-while-hidden GPU-surface transition.
switchRenderer cookie/auth migration assumes a single source→target pair.
- Dropping the
wkRenderer singleton breaks the load-bearing serverState.wkRenderer === tab.renderer active-tab state-sync guard and the startup non-nil-renderer invariant.
- Codex root-cause: using global
handlerContext.renderer as both API target and view source; multi-window can reparent a CEF view across containers.
Recommended approach (prototype-first)
- Prove the CEF lifecycle in isolation under ASan: two
CEFRenderers, route activation through the existing willDeactivate/didActivate/scheduleSurfaceRefresh sequence, never load until onBoundsReady, switch 20× and close one. If unstable → fall back to single CEF browser navigating between tab URLs (descriptors), which removes the concurrency hazards entirely.
- Make renderer ownership single-source-of-truth (per-tab) before un-gating handlers.
Acceptance
tab new <url> opens and shows the URL on chromium; switch/close/list work; no CrBrowserMain crash across 50 rapid tab ops; WebKit multi-tab unregressed.
Goal
Make tab management (
tab new <url>, switch, close, list) work on the Chromium (CEF) engine. Today these returncefUnsupportedErrorandTabis hardcoded toWKWebViewRenderer.Why deferred
An adversarial design review (Claude + Codex, both NO-GO) on a per-tab-engine / multi-CEF-browser design found it multiplies the documented navigate-while-hidden
CrBrowserMaincrash. The single-CEF path only survives today becauseServerState.switchRenderercarefully sequences deactivate → migrate → wait-for-attachment → activate (+ surface refresh). The tabaddTab/activateTabpath has none of that choreography. Additional verified blockers:CEFRendererhas no publiccloseBrowser(); closing a CEF tab risks teardown-while-attached (RendererContainerView never removes CEF views).switchRenderercookie/auth migration assumes a single source→target pair.wkRenderersingleton breaks the load-bearingserverState.wkRenderer === tab.rendereractive-tab state-sync guard and the startup non-nil-renderer invariant.handlerContext.rendereras both API target and view source; multi-window can reparent a CEF view across containers.Recommended approach (prototype-first)
CEFRenderers, route activation through the existingwillDeactivate/didActivate/scheduleSurfaceRefreshsequence, neverloaduntilonBoundsReady, switch 20× and close one. If unstable → fall back to single CEF browser navigating between tab URLs (descriptors), which removes the concurrency hazards entirely.Acceptance
tab new <url>opens and shows the URL on chromium; switch/close/list work; noCrBrowserMaincrash across 50 rapid tab ops; WebKit multi-tab unregressed.