Skip to content

fix(browser): stop host-wide preview failures and recover CDP sessions - #70

Merged
nickrroberts merged 6 commits into
mainfrom
fix/browser-stability-p0
Oct 21, 2026
Merged

nickrroberts merged 6 commits into
mainfrom
fix/browser-stability-p0

Conversation

@nickrroberts

@nickrroberts nickrroberts commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The built-in browser failed host-wide: one slow call made the server drop the whole automation host, failing every thread's pending calls with PreviewAutomationExecutionError and then "No preview automation host is available" until it reconnected. The error never said why. Audit: audits/2026-10-21-browser-stability-upstream-audit.md in the Control Plane project folder.

What

Not imported: the upstream server-browser rewrite (pingdotgg#15328), the reverted pingdotgg#19931 / pingdotgg#19377, and other P1 items.

Verification

  • New regression tests: broker eviction/non-eviction across threads, probe timeouts, grace replies, focus-only liveness, reason forwarding; host deadline; sanitizer; debugger detach/crash/bounded recovery; warmup bound; stable order; killed reload. Each broker/desktop fix test fails on origin/main.
  • Real runtime (isolated dev desktop, CDP fault injection): guest renderer crash leads to an actionable fail-fast, then recovery after reload with evaluate/snapshot/screenshot/click OK. SIGKILL of the main renderer logged reason: killed, recovering: true and the bridge returned.
  • Full per-package tests, typecheck and lint compared with origin/main: no new failures (details in PR comment).

Known limit

Background (not on screen) tab screenshots can still time out in the real app. They now report the reason instead of a bare error, and no longer take the host down. Tracked as follow-up (upstream pingdotgg#19912, pingdotgg#17015).

nickrroberts and others added 5 commits October 21, 2026 16:50
…ser host

The broker disconnected the automation host on any unanswered request,
failing every pending call from every thread and leaving agents with
"no automation host" until it re-registered. The 500ms status read sent
after each action could trigger it on any busy page.

- Wait timeoutMs plus a 1s grace (upstream pingdotgg#17693) so the host's own
  timeout reply wins the race.
- Never evict on background status reads (updateCurrentTab: false).
- Evict only when the host went silent since the request was delivered;
  a host answering other calls keeps its connection.
- Forward a sanitized failure reason from the web host so
  PreviewAutomationExecutionError says why it failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ording warmup

- Reattach a tab's CDP session when Chromium drops the debugger on its
  own, instead of failing every later command (upstream pingdotgg#17525).
- Fail cleanly when a guest is already destroyed (from upstream pingdotgg#14727).
- Bound the recording warmup capture so a stalled capturePage cannot
  hold the tab lock forever (upstream pingdotgg#20085).
- Fold the sanitized cause of a PreviewOperationError into the IPC
  failure text, so renderer and agent see e.g. a capture timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stroy them

Electron destroys a webview's guest when its element moves, so following
the server's list order blanked tabs and dropped their debugger sessions
mid-automation (upstream pingdotgg#13799).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The automation host lives in the main renderer, so a killed renderer left
agents with no browser host and a white window (upstream pingdotgg#20300).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Release a crashed guest's debugger session so in-flight commands
  reject, fail fast with a reload hint until the page reloads, bound
  CDP domain enabling to 5s, and cap reattach attempts per guest.
- The web host answers every request within its budget, so one slow
  operation can no longer look like a dead host.
- Only responses count as host liveness; focus updates travel on a
  separate RPC.
- Sanitizer covers Bearer/Basic values, JSON and key=value credentials,
  URL userinfo, spaced macOS paths and Windows forward-slash paths,
  without redacting ordinary words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Oct 21, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nickrroberts

Copy link
Copy Markdown
Collaborator Author

Verification (local, no remote CI)

Full per-package suites vs origin/main cc4d7b45ec:

  • Failing test names are identical: server 51, web 9, desktop 4, scripts 1. All pre-existing.
  • Baseline desktop also had 3 test files that failed to load. They pass on this branch.
  • client-runtime, contracts and shared pass on both.
  • typecheck errors are identical to baseline: contracts orchestration.test.ts, desktop DesktopWindow.ts zoom, and scripts.
  • lint: 740 findings, identical to baseline.

Tests that fail on origin/main and pass here:

  • broker: "does not evict a host still answering other threads", "slow background status read never drops the host", "reply within grace", "sanitized failure reason"
  • desktop: "reattaches a debugger that Chromium dropped", "releases the tab when a recording warmup capture never settles", "reloads a killed renderer"

Real runtime (isolated dev desktop, CDP fault injection):

  • Healthy tab: status, evaluate, snapshot, screenshot and click all OK.
  • Page.crash on the guest: evaluate and click fail in a few ms with "renderer crashed. Reload the tab to continue." Before this change they hung for more than 200s. After a reload everything works again.
  • SIGKILL of the dev main renderer: logged reason: killed, recovering: true, and a new renderer came back with the preview bridge.
  • Hidden offscreen guest: snapshot fails with capturePage ... TimeoutError: Operation timed out after '1s' instead of a bare error.

Independent review: no blocking issues. The 3 mediums (sanitizer coverage, crash stall, slow-host eviction) and the liveness, over-redaction and typing lows are fixed in bde4f9c and c55e111. Not changed: the killed-renderer reload is not gated on quitting. It stays bounded at 3 per 60s and re-checks isDestroyed.

Not proven at runtime: the broker path end to end through MCP. It needs a provider session, so it is covered by unit tests only.

@nickrroberts
nickrroberts merged commit 88c69a9 into main Oct 21, 2026
6 of 15 checks passed
@nickrroberts
nickrroberts deleted the fix/browser-stability-p0 branch October 21, 2026 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant