Skip to content

fix: step commands see shadow DOM and custom controls; refs no longer go stale - #46

Merged
karngyan merged 3 commits into
mainfrom
fix/step-commands-shadow-dom
Sep 28, 2026
Merged

karngyan merged 3 commits into
mainfrom
fix/step-commands-shadow-dom

Conversation

@karngyan

Copy link
Copy Markdown
Contributor

Why

The reins do benchmark showed Claude, driving reins step by step, failing tasks because of the step commands themselves, not because of its reasoning:

  • reins snapshot didn't look inside shadow DOM, so MDN's search and Open Library's sort menu were invisible.
  • Clicks on wizard cards and settings toggles failed with "element has zero size". The cause was stale refs, not hidden inputs.

What

  • Stale refs (the real "zero size" bug). reins snapshot never cleared the previous snapshot's data-reins-ref tags. After a wizard step or tab panel changed, a now-hidden element kept its old e8. The new snapshot gave e8 to a visible element too, and querySelector returned the hidden one first. Each snapshot now clears the old tags before tagging.
  • Shadow DOM in snapshots. reins snapshot lists elements inside open shadow roots and names them the way reins do does: through aria-labelledby, labels, slots and composed text. The helpers moved from jev-snapshot.ts into a shared page-dom.ts, so both snapshots use one implementation. --ref reaches shadow elements in click, type, fill, hover, select, scroll, text, wait and upload. --selector stays light-DOM CSS, and that's documented. Closed shadow roots stay invisible.
  • Controls with no box. A native radio or checkbox shrunk to 0×0 under a styled card is clicked through its visible <label> or its role=radio/switch/checkbox/option ancestor. A display: contents wrapper is clicked through its first child that has a box. The disabled, covered and moving checks apply to the element actually clicked. Hit testing now follows slotted content to its slot.
  • release.yml installs Chrome and sets REINS_TEST_CHROME the same way ci.yml does. The release run on feat(extension): jev_observe / jev_act for reins do (2/3) #42 failed on the browser suite's setup without this.
  • Benchmark fixture. In wizard.html, .backdrop { display: flex } overrode hidden, so the modal was open on load in every run. That's fixed. The benchmark report and the /docs/benchmarks page now note which step-by-step failures these fixes address.
  • Changeset: patch for @karnstack/reins and @reins/extension, written without em dashes so the website's changelog prose check passes.

Behaviour change to know about: the snapshot now filters with checkVisibility instead of offsetParent. It now includes fixed-position elements and drops visibility: hidden ones, so ref numbers can shift on some pages. Switches, labelled inputs and selects now get their real names instead of their text content.

Testing

  • pnpm build, pnpm lint and pnpm typecheck are clean. Tests pass: protocol 95, CLI 509, extension 325.
  • The browser suite has 7 new cases: shadow DOM snapshot, click and type by ref, a nested shadow root with slotted names, a 0×0 radio card, a role=switch, a stale ref, and display: contents. The 5 cases for stale refs, 0×0 and display: contents fail on the old code.
  • Live on a logged-in Chrome:
    • MDN: the snapshot lists button "Search the site" from inside mdn-search-button's shadow root. Clicking it by ref opened search, and typing by ref returned results.
    • wizard.html: clicking the Team card by ref checked it, and the review step showed Team.
    • settings.html: clicking the switches by ref after a tab change toggled the right ones, and Save stored them.

🤖 Generated with Claude Code

karngyan and others added 3 commits September 28, 2026 22:07
The release job ran pnpm test against whatever Chrome the runner had
preinstalled, and failed once in the browser suite's setup hook. Use the
same setup-chrome step and REINS_TEST_CHROME env as ci.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
reins snapshot walked document.querySelectorAll only, so controls in web
components (MDN's search button, openlibrary's Sort by menu) never got a
ref. It now reuses reins do's page helpers, moved to page-dom.ts: it walks
open shadow roots and names elements through aria-labelledby, labels,
shadow roots and slots. Refs resolve through open shadow roots for click,
type, fill, hover, select, scroll, text, wait and upload. --selector stays
light-DOM CSS.

"element has zero size" on the wizard's Team card and the settings
switches came from stale refs: a snapshot never cleared the previous
one's data-reins-ref tags, so an element hidden since (the wizard step or
tab panel just left) kept e8 while the new snapshot gave e8 to the switch,
and querySelector found the hidden one first. Each snapshot now clears the
old tags before tagging.

actionPoint also presses a stand-in for a target with no box: a 0x0 or
display:none native radio/checkbox is pressed through its visible label or
the custom radio/switch/checkbox/option it sits in, and a display:contents
element through its first rendered child. Disabled, covered and moving
checks apply to the element pressed, and disabled to the original too.
The hit test now walks the flat tree (assignedSlot), so a caption slotted
through two shadow roots counts as inside its button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ep-command fixes

.backdrop { display: flex } overrode the hidden attribute, so the New
project modal was already open on load in every benchmark run. The
report and page now say the snapshot and stale-ref bugs behind some
step-by-step failures were fixed after the benchmark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@karngyan
karngyan merged commit 50170ef into main Sep 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant