Skip to content

Name iframes in the ACT snapshot - #28

Merged
brynary merged 3 commits into
jev-drag-scrollfrom
jev-iframe-title
Oct 5, 2026
Merged

brynary merged 3 commits into
jev-drag-scrollfrom
jev-iframe-title

Conversation

@brynary

@brynary brynary commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #27. Playwright's AI snapshot shows every iframe without a name, even one with a title. So in scroll-in-frame ("scroll down 50% inside the incident history") Jev could not tell which frame was meant, and it passed 5 of 6 runs to the model.

Change

After the shim takes the ACT snapshot, whole-page or scoped, it names each unnamed iframe with its aria-label, or else its title: - iframe [ref=e4]: becomes - iframe "Incident history" [ref=e4]:. The snapshot is still one string, so the model's prompt, Jev's candidates, and report lines all get the name, with no Rust or protocol change.

  • Refs resolve through aria-ref=, including nested and cross-origin frames (f1e3).
  • A replaced ref, a failed read, or a spent step budget leaves the line as it was. Each read waits at most 1 s, and the names never fail the step.
  • Names are quoted as Playwright quotes them. Unlike Playwright, the shim never wraps a whole iframe line in single quotes (for a name with : ), because Rust's snapshot parsers read the role from the start of the line.

Evals

Both jev: variants, the 11 frame tasks, three runs each. Summary: evals/act/results/2026-09-27-local-jev-iframe-title.md.

pass Jev chose, scroll-in-frame p50 ACT, scroll-in-frame
#27 66/66 1 of 6 1.1s (Flash-Lite), 2.5s (Luna)
This PR 66/66 6 of 6 0.4s, 0.4s

The other 10 frame tasks are unchanged: Jev still chooses every action, with the same requests and model calls.

Tests

  • Shim unit tests: the rewrite rules, a replaced ref, a failed read, and a spent budget.
  • Rust unit tests: both snapshot parsers read the named line, and Jev's outline sees the iframe as a named container.
  • ACT: Jev's request carries both frames' titles and Jev scrolls inside "Incident history" with no model call (SCROLL role:iframe "Incident history" to 50%); a scoped ACT names a nested frame, prefers aria-label to title, names a cross-origin frame, and leaves an untitled frame as it was.
  • mise run check passes. SPEC §7.4, the shim protocol doc, and the CHANGELOG describe the change.

Full set

Both jev: variants then ran all 54 local tasks three times each on d9afb8a. The summary is evals/act/results/2026-09-27-local-jev-iframe-title.md, which replaces the frame-only one. Every run passes. Jev now chooses 84% and 85% of actions, up from 83% on #27, and model calls fall from 0.28 to 0.26 and 0.25 per task. Jev's share changed on three tasks:

task #27 this PR why
scroll-in-frame 1/6 6/6 the iframe's title names it
saved-google-flights 0/6 3/6 the page has two iframes
plan-by-seats 6/6 5/6 no iframe on the page: run-to-run noise

🤖 Generated with Claude Code

brynary and others added 2 commits September 27, 2026 08:52
Playwright's AI snapshot shows every iframe without a name, even one with
a title. On the framed-feed eval page, the frame for "scroll down 50%
inside the incident history" was only `- iframe [ref=e4]:`, so with --jev
Jev was not sure it was the incident history, and the model planned the
step in 5 of 6 runs.

Right after the snapshot, the shim now resolves each iframe line's ref
with aria-ref=, which works in nested frames and across origins. It adds
the iframe's aria-label, or else its title, as the name:
`- iframe "Incident history" [ref=e4]:`. Whole-page and scoped snapshots
both get names. The name reaches the model's prompt, Jev's candidates, and
the report lines, which already read names from snapshot lines.

An iframe without a name, a ref that no longer resolves, a failed read,
or a spent budget leaves the line as it was, so the names never fail a
step. The shim does not wrap a line in YAML quotes as Playwright does for
a name with ": ", because Rust's line parsers read the role from the
start of the line.

Tests cover the shim's rewrite rules, both Rust parsers on a named line,
a Jev scroll inside a titled frame with no model call, a scoped snapshot
with nested, labelled, cross-origin, and unnamed frames, and a
cross-origin frame in Firefox and WebKit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both jev: variants ran the 11 local tasks that use frames three times
each on 10b05d2. All 66 runs pass, as before.

In scroll-in-frame, Jev now chooses 6 of 6 actions, up from 1 of 6: it
sees the frame as "Incident history" and needs no model call. The step's
median ACT time falls from 1.1s to 0.4s with Gemini and from 2.5s to 0.4s
with GPT-5.6 Luna, and its cost from about $0.0003 to $0.0001 a run.

The other 10 frame tasks do not change: every action is still Jev's, with
the same model calls and Jev requests. Their frames' titles now reach Jev
as the named sections around the button, even five frames deep and across
sites. Their median ACT time moves from 472ms to 498ms and 483ms, within
the spread between runs. The session cost about $0.006.

The summary is kept apart from today's committed summaries, which the
script would have overwritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both jev: variants ran all 54 local tasks three times each on d9afb8a.
Every run passes. Jev now chooses 84% and 85% of actions, up from 83%
on #27, and model calls fall from 0.28 to 0.26 and 0.25 per task.

Jev's share changed on three tasks:
- scroll-in-frame: 1 of 6 to 6 of 6. The iframe's title names it.
- saved-google-flights: 0 of 6 to 3 of 6. The page has two iframes.
- plan-by-seats: 6 of 6 to 5 of 6. The page has no iframe, so this is
  run-to-run noise.

This summary replaces the frame-only one; it includes those runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@brynary
brynary added this pull request to stack #55 October 5, 2026 13:05
@brynary
brynary merged commit 6064828 into pointer-buttons Oct 5, 2026
3 checks passed
@brynary
brynary deleted the jev-iframe-title branch October 5, 2026 18:29
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