Skip to content

navigate / back / forward leave the AX tree stuck on the previous page (cdpSwitchToTab fast-path stale cache) #36

@apireno

Description

@apireno

Summary

Calling `navigate ` on an existing tab updates the document but leaves DOMShell stuck on the previous page's AX tree. `ls`, `text`, `extract_links`, and friends keep returning the old tree; node count stays frozen across multiple pages.

Severity varies by handler:

Handler Severity Notes
`navigate` 🔴 Severe — sticky Stale tree persists across every subsequent command. Workaround: use `open` (new tab) but it leaks tabs.
`back` 🟡 Mild — self-healing Immediate response reports stale `nodeCount`; next command's `ensureFreshTree` recovers.
`forward` 🟡 Mild — self-healing Same as `back`.

Surfaced by independent agent reports on 2026-05-25, including a multi-page LinkedIn scrape that stayed stuck at 284 nodes across messaging → connections → a profile page.

Root cause

`cdpSwitchToTab` has a fast path keyed on `(nodeMapTabId === tabId && nodeMap.size > 0)` — correct when re-entering an unchanged tab. But `handleNavigate` reuses the same `tabId` after pointing the tab at a new URL:

```typescript
await cdp.detach();
state.activeTabId = null;
await chrome.tabs.update(tabId, { url }); // same tabId, new page
// ...
const { nodeCount } = await cdpSwitchToTab(tabId); // fast path returns stale nodeMap
```

Neither `cdp.detach()` nor `state.activeTabId = null` invalidates the module-level `nodeMap` / `nodeMapTabId`. The fast path matches and returns the pre-navigation tree.

`handleClose` already does the right thing (clears `nodeMap` and `nodeMapTabId`) — `navigate`, `back`, `forward` just forgot to.

Secondary symptom

A `wait` issued right after `navigate` errors with `"Not attached to any tab. Run 'attach' first."` — because the `cdpSwitchToTab` fast path sets `state.activeTabId = tabId` but does not call `cdp.attach(tabId)`. The state says attached, the CDP target is gone, the next CDP call fails. Same root cause; same fix resolves it.

Why `treeStale` doesn't auto-recover

The CDP event listener filters `Page.frameNavigated` events by `source.tabId === state.activeTabId`. During `handleNavigate`, `state.activeTabId` is set to `null` while the navigation fires, so the event is dropped and `treeStale` never flips. The bug persists indefinitely until some other command sets `treeStale = true`.

Fix

Add `invalidateTreeCache()` helper (clears `nodeMap`, `nodeMapTabId`, `textContentCache`) and call it before `cdpSwitchToTab(tabId)` in `handleNavigate`, `handleBack`, `handleForward`. Forces the fast path to fail → slow path runs → `cdp.attach()` + fresh `getAllFrameAXTrees()`.

Scope

This is the 1.3.0 in-flight Chrome Web Store review — re-uploading the fixed package before approval so users never see the broken navigate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions