Skip to content

e2e: a screen's page says what it loaded - #790

Merged
futurepaul merged 2 commits into
masterfrom
claude/agent-smoke-watched-screen
Oct 31, 2026
Merged

futurepaul merged 2 commits into
masterfrom
claude/agent-smoke-watched-screen

Conversation

@futurepaul

Copy link
Copy Markdown
Collaborator

On preview, agent-smoke's first screen page (run e5415519fd, 2026-10-31) never ran its script. For 90 s it named no agent and kept its HTML's own "Connecting to the screen…", while every page opened after it connected and drew. Its FAIL had nothing to say about which request failed.

What changes: each screen page (agent-smoke's three, bot-mode's one) is opened watched (open_watched) until it connects or PAGE passes. A FAIL's detail now carries loading:

  • each request and its answer: a status, failed net::ERR_…, or no answer;
  • each socket (socket /p/6080/control?… 101, closed);
  • each error answer's body, which says whose refusal it is (the cell's port or the bridge's screen server), with its cf-ray to find it in the Worker's logs;
  • the page's console, its exceptions, and the browser's log.

Watching stops there (Browser::unwatch, which turns off its Network events): an open screen's socket streams every RFB frame as an event. A ticket's one-time secret is never said: its query is dropped.

Only diagnostics: no check, wait or bound changed.

Tests: a_page_says_each_request_and_its_answer (a ticket's redirect, a module answered 502, one failed, one never answered, a socket, the edge id's header in any case, and no ticket secret). Clippy is clean for fragment-e2e. Its proof on preview is the next hosted agent-smoke run from this branch (reported in a comment here).

🤖 Generated with Claude Code

agent-smoke's first screen page on preview (run e5415519fd, 2026-10-31)
never ran its script: no agent named, its HTML's own status, for 90 s,
while every page opened after it connected. Nothing said which of its
requests failed.

Each screen page (agent-smoke's three, bot-mode's) now opens watched until
it connects or PAGE passes, and a FAIL's detail carries what it said: each
request and its answer (a status, a failure, or none), each socket, each
error answer's body (the cell's refusal or the bridge's) with its cf-ray,
its console, its exceptions and the browser's log. Watching stops there
(Browser::unwatch): an open screen's socket streams every frame. A
ticket's one-time secret is never said. Diagnostics only: no check
changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@alexlwn123 alexlwn123 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fail for now at fcec0464b9cbd63c5479886965480dfbde849569.

The load diagnostics fit the stated purpose, but their output does not preserve the ticket-secret boundary.

Blocking:

  1. crates/e2e/src/lanes/agent_smoke.rs:463 copies Log.entryAdded.entry.url verbatim into loading.log. When the initial /__ticket?t=...&next=... navigation fails (for example an edge 502 before redemption), Chrome's failed-resource log carries that URL. Only requests() strips its query; this log path bypasses that sanitizer, and Suite::fail prints the resulting JSON. The ticket can still be usable: PAGE is 90 seconds, while TICKET_TTL_MS is 120 seconds and redemption is what consumes it. This exposes a computer sign-in credential in failure logs, contrary to docs/secrets.md and this PR's explicit no-ticket-secret promise.

Redact the ticket before any diagnostic string leaves loading, covering the log URL and occurrences in free-form log text, console/exception text, and response bodies, rather than only the request summary. Add a failed-ticket Log.entryAdded fixture and assert the complete serialized loading detail contains no ticket value. The existing test covers only requests() and cannot catch this bypass.

Validation: cargo test -p fragment-e2e a_page_says_each_request_and_its_answer -- --nocapture passes; git diff --check passes. CI remains in progress. This finding is based on the source/data flow, not a live browser reproduction: Chrome is unavailable here. The referenced /Users/futurepaul/dev/finite/engineering-style/engineering-style.md is also absent. No hosted/paid run was performed.

The implementation size otherwise looks appropriate for the diagnostic scope; no additional complexity finding.

@futurepaul

Copy link
Copy Markdown
Collaborator Author

Preview run from this branch (fcec0464), --only agent-smoke, run e54706d6df against deploy 0f6b26d59c7f: 33 passed, 0 failed, 22 model calls ($0.144), 169.5 s.

  • Every screen page opened watched and connected, so no FAIL detail was printed.
  • The page left open followed the agent's browser after its watching had stopped (unwatch), as did the pages opened later. Watching changes nothing a check sees.
  • Earlier run e5415519fd's first-page failure did not recur, so its cause is still unknown. The next time it happens, its FAIL will name the request.

Review (alexlwn123): only requests() dropped a ticket's query; the
browser's log entry for a failed ticket navigation carried its URL
verbatim, as could its text, the console, an exception or an error's
body. A ticket whose navigation failed is still good (PAGE is 90 s, a
ticket lives 120 s), so a FAIL could have printed a sign-in.

open_screen takes the secret from the ticket's URL it minted, and
said_loading (now pure) says it as <ticket> in every string it returns,
before any is cut to BODY_MAX (a cut first could keep part of it). Its
test reads the whole detail, as Suite::fail prints it, for any 12
characters of the secret; it fails when the cut comes first and when
nothing is hidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@futurepaul

Copy link
Copy Markdown
Collaborator Author

Thanks, that's right, and it's fixed in 9c4a731.

  • open_screen reads the ticket's secret from the URL it minted (ticket_secret). It refuses a ticket URL with no t=.
  • said_loading, now a pure function, writes the secret as <ticket> in every string it returns: request summaries, error bodies, the browser log's URL and text, console output and exceptions.
  • It redacts each string before cutting it to BODY_MAX. Cutting first could keep part of the secret.
  • New test a_page_says_nothing_of_its_ticket covers a failed ticket navigation, a Log.entryAdded with the ticket's URL in both url and text, the console, an exception, and an error body padded so a cut would split the secret. It checks the whole serialized detail, as Suite::fail prints it, for any 12 characters of the secret.
  • I checked that the test catches the bug both ways: it fails when the string is cut before redaction, and when nothing is redacted.

cargo test -p fragment-e2e --bin fragment-e2e agent_smoke (5 passed), clippy with -D warnings, and git diff --check are all clean.

🤖 Generated with Claude Code

@futurepaul
futurepaul requested a review from alexlwn123 October 31, 2026 02:18

@alexlwn123 alexlwn123 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass at 9c4a73129e28cf6d4a1a7ce0849c88e0151acdc6.

The earlier ticket-secret blocker is fixed: browser log URLs/text, console output, exceptions, request summaries and error bodies redact the minted ticket before diagnostic truncation. The new test checks the serialized failure detail, including a secret spanning the truncation boundary. The ticket issuer generates hex, so the extracted query value matches its diagnostic representation.

The change fits the screen-load diagnostic purpose, and the small pure formatter is an appropriate way to test the credential boundary. I found no remaining blocking regression or additional complexity concern.

Validation: cargo test -p fragment-e2e a_page_says -- --nocapture passed (2 tests); git diff --check HEAD~2 HEAD passed. CI remains in progress. No live browser or hosted/paid run performed in this review. The referenced engineering-style file is unavailable on this machine.

@futurepaul
futurepaul added this pull request to the merge queue Oct 31, 2026
Merged via the queue into master with commit c0656cb Oct 31, 2026
12 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.

2 participants