fix(browser): isolate timed-out snippets

Closed
MA
4mo ago
+529-30

Problem

browser_execute runs snippets in-process. Timing out the Effect fiber does not preempt the JavaScript Promise, so abandoned code could reconnect and send CDP commands after the caller received a timeout. Same-session tool calls may also execute concurrently.

Change

  • Permanently invalidate the exact Session object used by a timed-out snippet and remove it by identity from SessionStore.
  • Reject pending/future transport work, close active and connecting sockets, and stop profile polling promptly on invalidation.
  • Serialize browser_execute per session ID so a timeout cannot invalidate a healthy concurrent call; queued calls resolve the fresh Session after acquiring the lock.
  • Count queue wait against the configured timeout. A waiter that expires runs no code and does not invalidate the active Session.
  • Return recent console progress in the timeout error, capped to 8 KiB of valid UTF-8 with a truncation marker.
  • Stop console capture and onChunk updates after timeout.
  • Document the 60s default, 600s maximum, top-level timeout, and small logged batches in one guardrail.

Reproduction

Synthetic CDP tests cover a timed-out snippet that sleeps and later attempts Runtime.evaluate. The server receives no late command. A concurrently queued call then receives a fresh Session, reconnects, and executes successfully.

A separate queue-boundary test puts a 10ms call behind a 50ms same-session call. The queued call expires without running its snippet or invalidating the active Session; the first and a later call both complete normally. Additional tests cover pending waiters, connecting sockets, prompt cancellation of profile polling, UTF-8 byte capping, and stopped post-timeout capture.

Validation

  • Focused browser-execute.test.ts: 8 pass, 6 environment-gated skips
  • Full packages/bcode-browser suite: 27 pass, 8 environment-gated skips
  • Package typecheck passed
  • Pre-push filtered typecheck: 13/13 packages passed
  • git diff --check passed

This PR is stacked on #112 (session-recovery).