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.
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:
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.