Skip to content

feat(wait): carry a per-poll timeline in timeout failures - #2344

Open
thymikee wants to merge 1 commit into
mainfrom
claude/wait-poll-timeline
Open

feat(wait): carry a per-poll timeline in timeout failures#2344
thymikee wants to merge 1 commit into
mainfrom
claude/wait-poll-timeline

Conversation

@thymikee

@thymikee thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member

Summary

Diagnostics only; no timeout semantics change. Follow-up 4 from the review of #2331, prerequisite for #2343.

A wait timeout carried reason, readableCaptures, and waitedMs, which cannot say where the budget went. The runs behind #2343 spent a 10s budget on a single poll (5.8s runner findText on a fresh app, 3.4s of target discovery, a fallback cancelled at the deadline) and reported the same wait_capture_stalled as a dead runner would.

Change

error.details on every wait timeout now also carries:

  • captures: every poll attempted, readable or not.
  • polls[]: one entry per poll with startedMs on the wait's own clock, durationMs, and a typed outcome: readable, unreadable (content verdict the wait rode out), deadline (the deadline cancelled the capture in flight), or runner-restart (that cancellation carried restart evidence).

The top-level reason and the existing fields are unchanged; logPath still links the full request log. Long waits keep the first five and last twenty-five polls so the response stays compact. Whether a readable poll matched is the caller's verdict and is not recorded.

Example of the #2343 failure with this change:

"details": {
  "reason": "wait_capture_stalled",
  "captureStalled": true,
  "timeoutMs": 10000,
  "readableCaptures": 0,
  "captures": 1,
  "polls": [{ "startedMs": 0, "durationMs": 10285, "outcome": "deadline" }],
  "waitedMs": 10285
}

Validation

  • New tests: three polls (readable, unreadable, cancelled at the deadline) produce the expected records on the wait clock; a 40-poll wait keeps its first five and last twenty-five.
  • Existing wait suites pass (wait-polling, wait-text, wait-absent, wait-selector, wait-stable, daemon wait-runtime: 59 tests); root typecheck, oxlint, oxfmt, fallow clean.
  • Docs: website/docs/docs/commands.md wait-failure bullet; CHANGELOG entry.

A wait timeout said `reason`, `readableCaptures`, and `waitedMs`, so a
failure could not say where its budget went: the runs behind #2343 spent
a 10s budget on one poll (5.8s runner findText on a fresh app, 3.4s of
target discovery, a fallback cancelled at the deadline) and reported the
same `wait_capture_stalled` as a dead runner. The failure details now
carry `captures` and `polls[]`, one entry per poll with `startedMs` on
the wait's own clock, `durationMs`, and a typed outcome (readable,
unreadable, deadline, runner-restart), next to the unchanged reason and
the request-log link. Long waits keep the first five and last twenty-five
polls so the response stays compact.
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstack.github.io/agent-device/pr-preview/pr-2344/

Built to branch gh-pages at 2026-09-06 08:27 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.49 MB 4.49 MB +239 B
Package (unpacked) 4.49 MB 4.49 MB +239 B
Package (download) 1.33 MB 1.33 MB +116 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 25.1 ms 25.1 ms +0.1 ms
CLI --help 71.8 ms 70.2 ms -1.7 ms

@thymikee

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

The diagnostic change looks sound at 96e1a80, with one wording correction: not every wait timeout carries the timeline. wait --stable uses a separate error builder, and never-readable strict absence preserves its predicate failure. Please narrow the docs, changelog and PR description to the polling timeout paths that actually emit these fields; no need to expand the implementation here.

Android CI failed waiting for Alert result: cancelled. Its output does demonstrate the new timeline: 17 polls, 16 readable, then a deadline at 10,261 ms. That does not establish a regression from this change, but the failed lane still needs resolution before merge.

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