all repos — sz-chrome-remote-cdp @ ce30547af39f692bef777591bdb329a7fa00e86e

pi-browser-harness, patched to drive a Chrome on another host over CDP, with castle_cdp_search web search

fix(cdp): re-enable domains when re-attaching to a known tab

Every Target.attachToTarget mints a new sessionId and CDP domain enablement is
per-session, but switchTo only enabled domains on a tab's first visit. Switching
away and back left the refreshed session with Page, Network, Runtime and Log
disabled, so that tab silently stopped collecting console and network records and
stopped reporting dialogs and load events for the rest of the session.

Report: docs/superpowers/reports/2026-07-26-bug-audit.md#f3

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
amankumarsingh77 amankumarsingh7702@gmail.com
Tue, 28 Jul 2026 19:42:25 +0530
commit

ce30547af39f692bef777591bdb329a7fa00e86e

parent

d3fb25a8e1297f00dbf7ce4a188b12290b594c73

2 files changed, 68 insertions(+), 3 deletions(-)

jump to
M src/cdp/session.ts → src/cdp/session.ts

@@ -369,12 +369,11 @@ if (existing) {

// Each Target.attachToTarget produces a new sessionId — update it. sessionIdToTargetId.delete(existing.sessionId); existing.sessionId = attachedSessionId; - sessionIdToTargetId.set(attachedSessionId, tid); } else { tabs.set(tid, tab); - await enableDomains(attachedSessionId); - sessionIdToTargetId.set(attachedSessionId, tid); } + sessionIdToTargetId.set(attachedSessionId, tid); + await enableDomains(attachedSessionId); // Update global pointers to point at the new active tab sessionId = tab.sessionId; targetId = tid;
A test/cdp/session-switch-test.ts

@@ -0,0 +1,66 @@

+import { test, describe } from "node:test"; +import assert from "node:assert/strict"; +import { createCdpSession } from "../../src/cdp/session"; +import { createOwnershipRegistry } from "../../src/cdp/ownership"; +import { createStubTransport } from "../domains/fake-client"; +import { ok } from "../../src/util/result"; + +const ENABLED_DOMAINS = ["Page", "DOM", "Runtime", "Network", "Accessibility", "Log"]; + +const twoTabSession = async () => { + const stub = createStubTransport({ + "Target.setDiscoverTargets": ok({}), + "Target.getTargets": ok({ + targetInfos: [ + { targetId: "t1", type: "page", title: "One", url: "https://one.test/" }, + { targetId: "t2", type: "page", title: "Two", url: "https://two.test/" }, + ], + }), + "Target.attachToTarget": [ok({ sessionId: "s1" }), ok({ sessionId: "s2" }), ok({ sessionId: "s3" })], + "Browser.getWindowForTarget": ok({ windowId: 7 }), + "Target.activateTarget": ok({}), + }); + const ownership = createOwnershipRegistry({ ownedTargetIds: ["t1", "t2"] }); + const session = createCdpSession(stub.transport, ownership); + const attached = await session.attachFirstPage(); + assert.equal(attached.success, true); + return { stub, session }; +}; + +const enablesFor = (stub: { calls: ReadonlyArray<{ method: string; sessionId: string | null | undefined }> }, sessionId: string): string[] => + stub.calls.filter((c) => c.sessionId === sessionId && c.method.endsWith(".enable")).map((c) => c.method); + +describe("CdpSession.switchTo domain enablement", () => { + test("a first visit enables every domain on the new session", async () => { + const { stub, session } = await twoTabSession(); + const switched = await session.switchTo("t2"); + assert.equal(switched.success, true); + assert.deepEqual( + enablesFor(stub, "s2").sort(), + ENABLED_DOMAINS.map((d) => `${d}.enable`).sort(), + ); + }); + + test("returning to a known tab re-enables domains on its new session", async () => { + const { stub, session } = await twoTabSession(); + await session.switchTo("t2"); + const back = await session.switchTo("t1"); + assert.equal(back.success, true); + assert.equal(session.current()?.sessionId, "s3"); + assert.deepEqual( + enablesFor(stub, "s3").sort(), + ENABLED_DOMAINS.map((d) => `${d}.enable`).sort(), + ); + }); + + test("calls on the returned-to tab are routed to its refreshed session id", async () => { + const { stub, session } = await twoTabSession(); + await session.switchTo("t2"); + await session.switchTo("t1"); + const r = await session.call("Page.bringToFront", {}); + assert.equal(r.success, true); + const last = stub.calls.at(-1); + assert.equal(last?.method, "Page.bringToFront"); + assert.equal(last?.sessionId, "s3"); + }); +});