[GH-ISSUE #2289] [Feature] Reuse an element found in an earlier browser capture (backendNodeId + loaderId) instead of a CSS selector #759

Open
opened 2026-10-15 18:28:03 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @0xRafie on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2289

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This request does not include credentials, private samples, or sensitive target data.

Area

Process capture or runtime observation

Current limitation

inspect_web_event_listeners selects its node with a CSS selector and inspects the first match in the main document (docs/web-runtime.md L47). An agent that has already found an element in an earlier inspect_web_page capture has no way to say "that node". It has to write a selector, which may match a different node or none, especially when the page has no stable ids or classes. The DOM snapshot does not keep text or attribute values (docs/browser-observation.md "Data minimization"), so building a precise selector from it is hard.

Use cases

  • Find a button in an inspect_web_page capture, then ask inspect_web_event_listeners for that exact node's listeners.
  • Later, possibly reference the same node from a compare_web_captures result or a scenario step. Not sure yet whether that is wanted.

Desired outcome and success criteria

A node in passive DOM Evidence can carry a reference that a later browser call on the same target accepts in place of selector. The call fails clearly as stale when the document changed, never by silently picking another node. Success: the listener result for a referenced node matches the result from a selector that uniquely matches the same node.

Expected interaction with targets

  • Launch or attach to a process
  • Read existing files or captured data

Target and scope details (optional)

Non-goals: no clicking or dispatching, no new retained text or attribute values, no reuse across documents or targets.

Open scope questions (I don't know the answers):

  • Evidence identity: the docs say stable keys exclude transient CDP script IDs (docs/browser-observation.md "Data minimization"). A backendNodeId is transient in the same way. Should it be kept out of Evidence identity and returned only as a side reference, so identical pages still produce identical Evidence?
  • Data minimisation: is a backend node id plus loaderId acceptable to retain at all, given that it only lets you point back at the live page?
  • Staleness rule: is a loaderId change the right point to invalidate references, or should it also compare frame id and target id? Same-document navigations keep the loader (docs/web-runtime.md L33), so a reference could survive a large SPA re-render and then fail at resolve time.

Verification available so far

I have a prototype or observed results

Verification details (optional)

Tested with my own CDP scripts only, not through REA. On Chromium 154 (Fedora, headed and headless), Chrome 154 and Brave 155 (macOS, headless), the backendNodeId for the same element stayed the same across separate CDP connections and could be resolved again. That included an element inside a cross-origin iframe after scrolling, in all four configurations. I did not test what happens to the ids after a full navigation beyond treating a new loaderId as stale.

Alternatives considered

  • CSS selectors (current): ambiguous, and hard to derive from a value-free DOM snapshot.
  • A DOM path or index from the snapshot: breaks as soon as siblings are inserted.
  • Leave it as is and let agents write selectors: works for simple pages.

Possible direction

An optional node_ref input to inspect_web_event_listeners (mutually exclusive with selector), made of { target_id, frame_id, loader_id, backend_node_id } from the earlier capture. REA would check that the loader is still current, then resolve the node with DOM.resolveNode / DOM.describeNode by backend id. This is only a proposal; I'd like a scope answer before any code.

References

  • docs/web-runtime.md (event listeners: L47-49; loader identity: L20, L33)
  • docs/browser-observation.md "Data minimization"
  • CDP DOM domain: BackendNodeId, DOM.resolveNode, DOM.describeNode; Page domain loaderId
  • Roadmap: #39, #774
Originally created by @0xRafie on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2289 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related proposal. - [x] I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here. - [x] This request does not include credentials, private samples, or sensitive target data. ### Area Process capture or runtime observation ### Current limitation `inspect_web_event_listeners` selects its node with a CSS `selector` and inspects the first match in the main document (`docs/web-runtime.md` L47). An agent that has already found an element in an earlier `inspect_web_page` capture has no way to say "that node". It has to write a selector, which may match a different node or none, especially when the page has no stable ids or classes. The DOM snapshot does not keep text or attribute values (`docs/browser-observation.md` "Data minimization"), so building a precise selector from it is hard. ### Use cases - Find a button in an `inspect_web_page` capture, then ask `inspect_web_event_listeners` for that exact node's listeners. - Later, possibly reference the same node from a `compare_web_captures` result or a scenario step. Not sure yet whether that is wanted. ### Desired outcome and success criteria A node in passive DOM Evidence can carry a reference that a later browser call on the same target accepts in place of `selector`. The call fails clearly as stale when the document changed, never by silently picking another node. Success: the listener result for a referenced node matches the result from a selector that uniquely matches the same node. ### Expected interaction with targets - Launch or attach to a process - Read existing files or captured data ### Target and scope details (optional) Non-goals: no clicking or dispatching, no new retained text or attribute values, no reuse across documents or targets. Open scope questions (I don't know the answers): - **Evidence identity:** the docs say stable keys exclude transient CDP script IDs (`docs/browser-observation.md` "Data minimization"). A `backendNodeId` is transient in the same way. Should it be kept out of Evidence identity and returned only as a side reference, so identical pages still produce identical Evidence? - **Data minimisation:** is a backend node id plus `loaderId` acceptable to retain at all, given that it only lets you point back at the live page? - **Staleness rule:** is a `loaderId` change the right point to invalidate references, or should it also compare frame id and target id? Same-document navigations keep the loader (`docs/web-runtime.md` L33), so a reference could survive a large SPA re-render and then fail at resolve time. ### Verification available so far I have a prototype or observed results ### Verification details (optional) Tested with my own CDP scripts only, not through REA. On Chromium 154 (Fedora, headed and headless), Chrome 154 and Brave 155 (macOS, headless), the `backendNodeId` for the same element stayed the same across separate CDP connections and could be resolved again. That included an element inside a cross-origin iframe after scrolling, in all four configurations. I did not test what happens to the ids after a full navigation beyond treating a new `loaderId` as stale. ### Alternatives considered - CSS selectors (current): ambiguous, and hard to derive from a value-free DOM snapshot. - A DOM path or index from the snapshot: breaks as soon as siblings are inserted. - Leave it as is and let agents write selectors: works for simple pages. ### Possible direction An optional `node_ref` input to `inspect_web_event_listeners` (mutually exclusive with `selector`), made of `{ target_id, frame_id, loader_id, backend_node_id }` from the earlier capture. REA would check that the loader is still current, then resolve the node with `DOM.resolveNode` / `DOM.describeNode` by backend id. This is only a proposal; I'd like a scope answer before any code. ### References - `docs/web-runtime.md` (event listeners: L47-49; loader identity: L20, L33) - `docs/browser-observation.md` "Data minimization" - CDP DOM domain: `BackendNodeId`, `DOM.resolveNode`, `DOM.describeNode`; Page domain `loaderId` - Roadmap: #39, #774
Author
Owner

@matbrgz commented on GitHub (Oct 12, 2026):

Design & Provenance Review Notes

Targeting DOM nodes via exact backend identity (backendNodeId + loaderId) rather than brittle CSS selectors significantly improves agent interaction reliability:

  1. CDP Stability: In Chrome DevTools Protocol, backendNodeId is persistent across DOM tree operations within the same document lifecycle (loaderId).
  2. Stale Node Protection: Pairing backendNodeId with loaderId enforces staleness detection: if navigation occurs (loaderId mismatch), the tool fails closed with stale_node_reference rather than inspecting an arbitrary node in a newly navigated document.
<!-- gh-comment-id:6134307519 --> @matbrgz commented on GitHub (Oct 12, 2026): ### Design & Provenance Review Notes Targeting DOM nodes via exact backend identity (`backendNodeId` + `loaderId`) rather than brittle CSS selectors significantly improves agent interaction reliability: 1. **CDP Stability:** In Chrome DevTools Protocol, `backendNodeId` is persistent across DOM tree operations within the same document lifecycle (`loaderId`). 2. **Stale Node Protection:** Pairing `backendNodeId` with `loaderId` enforces staleness detection: if navigation occurs (`loaderId` mismatch), the tool fails closed with `stale_node_reference` rather than inspecting an arbitrary node in a newly navigated document.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#759
No description provided.