Better Fetch

· Paul Crossland

After the Tab Switch: Proving Which Page Supplied the Data

Fresh agent and MCP races show why browser extraction must verify the active target generation instead of trusting a switch acknowledgement.

A browser agent opens a product page in one tab, a comparison page in another, and then asks to switch back before extracting a price. The tool reports success. The next selector also succeeds. Only later does anyone discover that the value came from the page the agent never left.

That is not ordinary selector flakiness. It is a provenance failure: the control plane claimed one active target while the extractor operated on another.

Fresh reports show two ways this happens. A Browser Use issue opened August 17 demonstrates that version 0.13.8 can return a success-shaped result when a requested tab no longer exists or a switch event produces no target. The message can enter long-term agent memory, so later steps reason from a transition that did not occur. An open replacement fix from August 19 changes those paths to explicit errors.

A separate Playwright pull request opened August 18 describes an MCP dashboard race: overlapping asynchronous tab aggregations can arrive out of order, allowing an older session snapshot to overwrite the newer selection. An August 20 follow-up reports that the Firefox session-switch test still fails after a longer timeout and proposes marking it as expected to fail while the product race remains. All of these changes are open, so they are current design and failure evidence, not released guarantees.

The practical thesis is: a tab or session switch is a state transition that must produce a verified target-generation receipt; a command acknowledgement, agent memory string, dashboard highlight, or successful selector cannot by itself prove which page supplied extracted data.

This is guidance for owned or properly authorized automation. Switching targets must never become a way to carry state around a login, challenge, payment boundary, denial, or source policy. Those outcomes stop or narrow the run regardless of which tab is active.

The repeated angle to avoid

Recent Better Fetch posts already cover principal handoffs, changing iframe graphs, browser-state checkpoints, control-plane telemetry, MCP evidence planes, and request-graph policy. The repeated article would say to log tab IDs and retry failed switches.

The new surplus is a transition contract between control and extraction. There are two independent questions: did the browser change its selected target, and did every observer converge on that same target generation before downstream work began? Retrying a switch or increasing a timeout does not answer either question when a failure is falsely reported as success or a stale snapshot wins a race.

Source map

Fresh primary evidence from the last seven days:

SourceDateContribution
Browser Use issue 54862026-08-17Reproduces stale or unknown tab IDs and missing event results being returned without an error, then written into agent memory.
Browser Use pull request 55002026-08-19Proposes surfacing the underlying switch error, rejecting an empty event result, and preserving a successful path only when a target ID is returned. It is open.
Playwright pull request 422902026-08-18Attributes stale session selection to overlapping tab aggregation and out-of-order completion rather than insufficient waiting. It is open.
Playwright pull request 423252026-08-20Reports continuing Firefox failures after a 30-second timeout, reinforcing that the mismatch is a state race rather than simple latency. It is open.

Older background is the browser target model itself: tabs, popups, pages, contexts, remote sessions, and dashboard views are related objects, not one global current_page. The operational synthesis below is to make their transition observable before any extracted field can inherit it.

A switch has four different outcomes

Treat these as separate signals:

  1. Intent accepted. The agent or deterministic runner requested target B using an alias, tab suffix, page handle, or session name.
  2. Transition executed. The browser-control handler resolved a live target and completed without an exception or empty result.
  3. Target observed. The execution surface reports that target B, in the expected browser context and session, is now the target for subsequent actions.
  4. Generation ready. Target B's current document generation reached the application-specific state required for extraction.

Browser Use's report breaks between the first two: an invalid target can still produce success-shaped memory. The Playwright report breaks between the second and third: session state can change while a dashboard observer later paints an older snapshot. A selector succeeding after either failure proves only that some page matched it. Shared navigation, common component libraries, and duplicated labels make that a weak identity check.

Readiness is another boundary. The right target can immediately navigate, replace its document, or hydrate after the switch. A target identity without a document generation can therefore bind one command to the correct tab and the extraction to stale or transitional content.

Issue a target-generation receipt

Do not let a switch tool return only prose. Emit a structured receipt and require it before the next queued action:

  • switch_attempt_id, run ID, principal class, tool version, browser product, and browser revision;
  • source session, browser context, target reference, and document-generation reference before the switch;
  • requested target alias plus the resolved full target reference, with sensitive values hashed in broad telemetry;
  • dispatch timestamp, handler result class, normalized error, and whether the event returned a non-empty target;
  • observed session, context, target reference, page origin class, and document generation after the switch;
  • convergence result across controller, browser session, agent state, and dashboard when a dashboard is operationally relevant;
  • readiness marker and timestamp, navigation or popup transition observed during verification, and policy outcome;
  • final verdict: verified, target_missing, handler_failed, observer_stale, generation_changed, policy_stop, or unknown.

The extraction job should carry the verified target_generation_id, not merely active_tab: 2. Every important field then points to that generation and to its network, DOM, accessibility, or screenshot evidence. If the generation changes mid-extraction, dependent fields become unknown or the operation restarts from a new receipt.

Avoid broad logging of complete authenticated URLs, page titles, cookies, tokens, private content, or screenshots. Origin classes, approved host identifiers, target-reference hashes, bounded title hashes, state classifications, and restricted artifact pointers are usually enough.

Make the transition atomic from the agent's view

A reliable orchestration sequence is small:

  1. Snapshot the live target set and current target generation.
  2. Resolve the requested alias to one live full target reference. Reject zero or multiple matches.
  3. Dispatch one switch and require an explicit non-empty result; exceptions and missing results are failures.
  4. Read the active target back from the same browser-control surface used for subsequent actions.
  5. Compare intended and observed session, context, target, and generation. A dashboard may be an additional observer, never the sole source of truth.
  6. Wait for a source-specific readiness marker within a bounded budget. Do not use a larger generic timeout to hide a lost update.
  7. Mint the receipt, then allow queued interaction or extraction.
  8. Invalidate the receipt on close, navigation, popup replacement, context reset, session handoff, or target detach.

This sequence prevents agent memory from becoming control state. Memory can summarize a verified receipt; it cannot manufacture one.

An owned-fixture switch test

Build the canary with pages and sessions you control:

  1. Open two pages with the same visible button text but distinct harmless data markers. Verify that selector success cannot substitute for target identity.
  2. Close one page, then request its old alias. Require target_missing, no queued extraction, and no success phrase in agent memory.
  3. Make the switch handler return no result without raising. Require handler_failed rather than inferred success.
  4. Delay title collection for the old session so its snapshot completes after the new session's snapshot. Confirm that sequence or generation checks reject the stale update.
  5. Switch to a live target that immediately navigates. Assert that no field is accepted until the post-navigation generation has its own readiness proof.
  6. Run rapid A-to-B-to-A transitions and concurrent observer refreshes. The final receipt must reflect ordering, not whichever asynchronous snapshot finishes last.
  7. Repeat across supported browser engines, remote-browser providers, MCP clients, and agent frameworks. Open fixes are not deployment guarantees; test the exact build in use.
  8. Return a challenge, login, denial, or payment surface after a valid switch. Require policy_stop; never reinterpret correct target selection as permission to continue.

The operator decision rule

When extracted data appears to come from the wrong page, find the earliest unverified transition. If target resolution failed or the handler returned no target, classify the switch as failed and discard every dependent action. If the browser switched but an observer stayed stale, repair observer ordering without replaying source requests. If the target matches but the document generation changed, re-establish readiness and provenance before extracting again. If identity cannot be reconstructed, quarantine the affected fields rather than trusting the agent transcript.

A browser agent can operate many pages efficiently, but current page is not a durable fact. It is a claim produced by asynchronous tools, browser sessions, observers, and document lifecycles. Make that claim earn a receipt, and the dataset can prove not only what value was extracted, but which page generation actually supplied it.