You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Those PRs all look useful individually, but they also point at a shared lifecycle problem around “what is the currently attached tab/session, and how do helpers recover when it is no longer live?”
Problem
browser-harness currently handles stale tab/session states in several focused places:
attach_first_page() picks a page target and enables default domains.
set_session updates self.session / self.target_id after switch_tab() and new_tab().
default domains are re-enabled after session changes so helpers like wait_for_network_idle() keep working.
current_tab has a not_attached path when target_id is missing.
cosmetic/best-effort work such as tab-title unmarking can still become a blocking operation if it talks to a dead renderer.
The result is that each new CDP edge case tends to be fixed locally with another timeout/string-match/reattach patch. That is pragmatic, but it makes it hard to know the intended invariant:
Before a helper performs a renderer-bound operation, what guarantees do we have about the current target/session? If those guarantees fail, where is recovery supposed to happen?
This is mostly visible in stale-target cases: closed tabs, discarded tabs, Chrome restarts, expired sessions, or WebSocket/session close paths.
Proposal
Add a small explicit internal contract for tab/session lifecycle recovery, without changing the public helper API initially.
Possible shape:
Define the daemon’s internal session states / failure classes, e.g.
no_session
attached
target_missing
session_stale
renderer_unresponsive
browser_disconnected
Centralize recovery in one small helper such as _ensure_live_session() / _recover_session() / _with_live_session() that is used by daemon request handling and session-changing paths.
Treat cosmetic operations, such as removing the controlled-tab marker from the old tab, as explicitly best-effort and bounded by a short timeout.
Keep the first implementation slice small and testable:
no behavior change for healthy tabs;
stale current session does not make switch_tab() / new_tab() hang indefinitely;
re-attach paths always re-enable Page, DOM, Runtime, and Network on the new session;
unrecoverable states return actionable errors instead of blocking forever;
Add unit tests with mocked CDP/IPC for the contract. Live Chrome discarded-tab / killed-session repros can remain manual or become a later integration fixture if the project wants that.
A deliberately small first PR could be just:
introduce the internal recovery helper / state classification;
Always create a fresh about:blank instead of attaching to an existing page. This avoids many stale-target cases but changes the current “attach to the user’s active/real tab” behavior, so it feels like a policy change rather than a bug fix.
Make this a large state-machine refactor. Probably too broad for a first contribution. I’d prefer a small internal contract + tests first, then incremental follow-ups.
Only add integration tests. Valuable eventually, but expensive and environment-dependent. A unit-level recovery contract would still catch most regressions around session state transitions and timeout behavior.
If this direction seems useful, I’m happy to open a small first PR that starts with one path and keeps the diff focused.
Before submitting
Related open PRs I found while checking overlap:
switch_tab()can hang when the previously attached session is stale/dead.no close frame received or sentshould trigger re-attach instead of surfacing as a hard failure.Those PRs all look useful individually, but they also point at a shared lifecycle problem around “what is the currently attached tab/session, and how do helpers recover when it is no longer live?”
Problem
browser-harnesscurrently handles stale tab/session states in several focused places:attach_first_page()picks a page target and enables default domains.set_sessionupdatesself.session/self.target_idafterswitch_tab()andnew_tab().wait_for_network_idle()keep working.current_tabhas anot_attachedpath whentarget_idis missing.handle()currently depends on specific error text such asSession with given id not foundand, in fix(daemon): re-attach on 'no close frame' WebSocket error #347,no close frame.The result is that each new CDP edge case tends to be fixed locally with another timeout/string-match/reattach patch. That is pragmatic, but it makes it hard to know the intended invariant:
This is mostly visible in stale-target cases: closed tabs, discarded tabs, Chrome restarts, expired sessions, or WebSocket/session close paths.
Proposal
Add a small explicit internal contract for tab/session lifecycle recovery, without changing the public helper API initially.
Possible shape:
no_sessionattachedtarget_missingsession_stalerenderer_unresponsivebrowser_disconnected_ensure_live_session()/_recover_session()/_with_live_session()that is used by daemon request handling and session-changing paths.switch_tab()/new_tab()hang indefinitely;Page,DOM,Runtime, andNetworkon the new session;A deliberately small first PR could be just:
Alternatives considered
about:blankinstead of attaching to an existing page. This avoids many stale-target cases but changes the current “attach to the user’s active/real tab” behavior, so it feels like a policy change rather than a bug fix.If this direction seems useful, I’m happy to open a small first PR that starts with one path and keeps the diff focused.