Files
webstudio/packages/vision
Oleg Isonen 5d10a7de60 fix: Recover responsive screenshots after DevTools disconnects (#6170)
## Summary

Recover responsive screenshot batches when the Browser DevTools
WebSocket closes transiently.

The capture session now treats a DevTools socket closure as the same
recoverable session failure as an unexpected browser exit. It restarts
Chromium once and reruns the complete viewport batch, so callers receive
a consistent set of screenshots instead of partial artifacts.

## Root cause

The DevTools socket close handler rejected pending commands with a
generic `Error`. The reusable browser retry boundary only recovered
typed browser-session closures or a browser process that had exited, so
a closed socket with a still-running Chromium process escaped as
`MCP_TOOL_FAILED`.

## Technical choices

- Classify a DevTools WebSocket closure as `BrowserSessionClosedError`
at the CDP boundary.
- Reuse the existing bounded browser-session restart path instead of
adding a separate MCP-layer retry.
- Retry the complete responsive batch once so results remain
all-or-nothing.
- Preserve the original `Browser DevTools connection closed.` diagnostic
when the replacement connection also closes.

## Impact

A transient DevTools disconnect during a responsive capture
automatically restarts the reusable browser and captures every requested
viewport. Repeated connection loss still fails after one retry without
looping indefinitely.

## Checklist

- [x] Add a fail-first regression for a two-viewport responsive capture
- [x] Verify mobile and desktop widths are both recaptured after
reconnect
- [x] Verify a second consecutive disconnect returns the original error
- [x] Independently verify recovery with real Chrome, CDP, rendering,
and PNG output
- [x] Review fixture impact: no fixture inputs or generated fixture
outputs are affected
- [x] Review documentation impact: no user-facing documentation changes
are required because this restores documented behavior
- [ ] Run agent evaluations (requires separate approval)

## Verification

- New responsive reconnect regression failed before the implementation
with `Browser DevTools connection closed.` and passes after it
- Independent real-browser harness with Google Chrome `151.0.7922.138`:
- served a real local responsive page and captured `375×812` and
`1440×900`
- forcibly closed the first real CDP WebSocket during
`Page.captureScreenshot`
- observed Chrome #1 terminate, its profile get removed, Chrome #2
launch, and the complete viewport batch replay
- produced valid PNGs at both requested dimensions and left no browser
processes or temporary profiles behind
- `pnpm --filter @webstudio-is/vision test` — 13 files, 81 tests passed
- `pnpm --filter @webstudio-is/vision typecheck`
- `pnpm --filter webstudio exec vitest run
src/commands/mcp-preview.test.ts` — 43 tests passed
- `pnpm --filter webstudio typecheck`
- `pnpm exec oxlint --deny-warnings
packages/vision/src/screenshot-browser-cdp.ts
packages/vision/src/screenshot-browser-cdp.test.ts`
- `pnpm exec oxfmt packages/vision/src/screenshot-browser-cdp.ts
packages/vision/src/screenshot-browser-cdp.test.ts`
- `git diff --check`

The real-browser fault was injected deterministically at the first
screenshot command rather than produced by an organic OS or network
failure. It exercised the reported DevTools closure boundary and
complete responsive-batch recovery.

Agent evaluations were not run because they require separate explicit
approval.

Closes #6169
2026-08-18 12:53:50 +02:00
..

Vision

@webstudio-is/vision provides source-agnostic browser capture, screenshot comparison, OCR analysis, caching primitives, and portable visual reports.

Import the smallest relevant entry point:

import { createBrowserScreenshotSession } from "@webstudio-is/vision/browser";
import { captureVisualEntries } from "@webstudio-is/vision/capture";
import { diffPngFiles } from "@webstudio-is/vision/diff";
import {
  classifyScreenshotComparisonReport,
  writeScreenshotComparisonReport,
} from "@webstudio-is/vision/report";
import { selectRepresentativeViewports } from "@webstudio-is/vision/viewports";

Consumers own their source-specific orchestration. The visual regression runner, for example, handles Git revisions and Storybook CSF rendering while this package handles capture batches, image comparison, and reports.