fix(understudy): prune descendant frame ownership and cached frame wrappers on detach and close
PR
2d ago+434+434+012345678901234567890123456789-30-30-01234567890123456789
Why
Closing a page or detaching a frame subtree in BrowserContext left child frame entries in frameOwnerPage and retained cached Frame wrappers, accumulating stale references across repeated page opens and closes (#3240). Process-swap detaches could also remove frames before their replacement session took ownership.
What changed
- In FrameRegistry, collect and return all detached subtree frame IDs, track swapping state during process swaps so topology is preserved until the replacement session attaches, and clean up session frames in detachSession.
- In Page, invalidate WebMCP state, frame cache, and frame ordinals for the detached frame and all its descendants. In dispose(), clear event disposers and caches safely even if individual disposers throw.
- In BrowserContext, sync frame ownership during tree seeding, prune descendant frame entries from frameOwnerPage on detachment and page destruction, and dispose open pages during context shutdown.
- Added 4 unit tests in understudy-context-oopif-adoption.test.ts covering 100-page nested-frame open/close cycles, subtree detach cleanup, process swaps, and resilient error recovery.
Test plan
- pnpm exec vitest run packages/extension/tests/understudy-context-oopif-adoption.test.ts passes (23/23 tests, including 100 nested page open/close cycles leaving zero stale entries in frameOwnerPage).
- pnpm exec vitest run packages/extension/tests/understudy-context-domain-policy.test.ts packages/extension/tests/page-webmcp-tools.test.ts packages/extension/tests/page-webmcp-invocations.test.ts packages/extension/tests/page-cdp-events.test.ts passes (89/89 tests).
- pnpm -F @browserbasehq/stagehand-extension typecheck and oxfmt check pass with 0 errors.
Closes #3240
Summary by cubic
Fixes stale frame ownership and cached Frame wrappers accumulating in BrowserContext when pages close or frame subtrees detach, which piled up across repeated page open/close cycles (#3240). Process-swap detaches now keep frame topology intact until the replacement session takes ownership.
FrameRegistryreturns all detached subtree frame IDs, tracks mid-swap frames, and prunes session-owned frames indetachSession.Pageinvalidates WebMCP state, frame cache, and frame ordinals for the whole detached subtree;dispose()clears caches and disposers safely even if an individual disposer throws.BrowserContextsyncs frame ownership during tree seeding, prunes descendant entries fromframeOwnerPageon detach and page destruction, and disposes open pages during context shutdown.- Added 4 unit tests covering 100 nested-frame open/close cycles, subtree detach cleanup, process swaps, and close-time error recovery.
Closes #3240.