#368·ego-lite

[Bug]: snapshotText assigns no ref to listener-bearing elements without an interactive role

Author: ysys143Created Sep 7, 2026Updated Sep 19, 2026

Affected component

ego-browser runtime or CLI

What happened?

snapshotText() gives every element an entry in the tree, but only assigns a [ref=N] handle to elements that are semantically interactive. An element that carries a click listener without an interactive role or tag appears as plain text, so there is no ref to click.

On ego lite 0.4.7.4 (Chromium 150.0.7871.101, Node v24.18.0), macOS 15.7.9 arm64, with this fixture:

xml
<button id="b1">plain button</button>
<ul>
  <li id="li1">Seoul City Hall (A-1001)</li>
  <li id="li2">Seoul Metropolitan Council (A-1002)</li>
</ul>
<ul>
  <li><button id="lb1">button inside item</button></li>
</ul>
<div id="clickable" role="button" tabindex="0">div with role=button</div>
<script>
window.__log = [];
for (const id of ['b1','li1','li2','lb1','clickable']) {
  document.getElementById(id).addEventListener('click', e => window.__log.push({ id, isTrusted: e.isTrusted }));
}
</script>

snapshotText() returns:

root
  heading
    text "ref probe"
  button [ref=6, loc=unstable]
    text "plain button"
  unordered_list
    list_item
      text "Seoul City Hall (A-1001)"
    list_item
      text "Seoul Metropolitan Council (A-1002)"
  unordered_list
    list_item
      button [ref=15, loc=unstable]
        text "button inside item"
  button [ref=17, loc=unstable]
    text "div with role=button"

The <li> elements are present in the tree, but carry no ref. They are nonetheless real click targets:

await click('xpath=//li[@id="li1"]')
await js('JSON.stringify(window.__log)')
// [{"id":"li1","isTrusted":true}]

A trusted click on the li fires its listener normally.

Why this matters in practice

From an accessibility standpoint this is arguably correct: a bare <li> with a click handler is not an interactive node. But agents meet this markup constantly. In one benchmark on a large shopping site the cart's delete control was a plain div with an onClick and no role.

When the ref path is unavailable, the agent falls back to CSS/XPath selectors or raw coordinates — which is exactly where #350 applies, since element-targeted mouse helpers can silently miss or hit the wrong element. So the observation gap here feeds directly into the actionability gap there.

What would help

Some way to reach listener-bearing, non-semantic elements through the same safe path as everything else. For example: an opt-in mode that surfaces elements with registered click/pointer listeners, or a documented query that returns refs for them.

snapshotText() does take a scope option (full_page / only_within_viewport) per the shipped skill docs. I have not verified whether any existing option changes ref assignment for these elements — if one already does, documenting it would resolve this.

Version

ego lite 0.4.7.4 — Chromium 150.0.7871.101, Node v24.18.0

Environment

macOS 15.7.9 (24G830), arm64; agent-driven ego-browser nodejs heredocs