iOS: XCTest-channel penalty keeps the runner in private-AX fallback most of a long session (fixed 3 s / 120 s, no override)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- ios, typescript
- Domain
- mobile, performance, testing
Research direction
Read the snapshot penalty and capture plan code under dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/, starting with RunnerTests+SnapshotTiming.swift, RunnerTests+SnapshotCapturePlan.swift, and the snapshot CLI entry point. Check the related issue #1542 and presentedSurface work in #3565 before choosing a scope. Done means the requested penalty controls and CLI backend option behave as specified, with tests covering single query timeouts and recovery probes.
Written by the indexing model from the issue text.
Description
Summary
On a heavy UIKit app (iPad simulator), one slow or timed-out XCTest-channel snapshot tier puts the runner into private-AX fallback for 120 s. A timed-out 1 s recursiveTree recovery probe re-arms it; that probe runs when the private-AX capture is rejected. And once the penalty expires, the next capture's 1 s query sweep often times out and penalizes the channel again. In one long-running session log, 71 % of snapshot commands ran with the XCTest channel deferred.
In our captures, private-AX returned presented screens together with the screen underneath them. A test then can't reliably tell which screen is top-most, and an element of the covered screen looks "visible". For read-only checks this is mostly harmless. For steps that must act on the right screen (bulk select / destructive bulk actions in a list), it's unsafe, so we refuse those steps whenever a fallback happened in the last 120 s.
Version / environment
- agent-device 0.21.25 (pinned by
@e2e-dev/mobile0.12.0, used through thee2e0.20.0 runner). The penalty logic is unchanged in 0.21.28 and 0.21.29-nightly.20261020. - Xcode 27.0 (27A266a), iOS 27.0 simulator runtime, iPad Air 11-inch (M4) simulators
- UIKit app with long table views
What the source shows (0.21.25, dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/)
- An XCTest-channel tier penalizes the channel when it times out, exhausts its deadline, or takes longer than
snapshotXCTestSlowCaptureThreshold(3 s):RunnerTests+SnapshotTiming.swift:119-155, constant atRunnerTests.swift:139. Budgets: tree slice 8 s (RunnerTests.swift:143), query sweep 1.0 s (RunnerTests+Snapshot.swift:134-143), viewport read ≤ 1.0 s (RunnerTests+SnapshotAcquisition.swift:50-56). A system-modal probe timeout also penalizes (RunnerTests+Snapshot.swift:360). penalizeSnapshotXCTestChannelsetspenaltyUntil = now + 120 s(RunnerTests+SnapshotCapturePlan.swift:133-143,RunnerTests.swift:122). While it's active, the plan puts private-AX first, plusrecursiveTreewith a 1 s slice (RunnerTests+SnapshotCapturePlan.swift:110, 256-277).- Each slow or timed-out XCTest attempt during the penalty re-arms it. In practice that's the 1 s tree probe, which runs when the private-AX tier fails or is rejected (
RunnerTests+SnapshotCapturePlan.swift:272, 391-431).penaltySuppressedapplies only to the one-shot warm-up after a target PID change (:304, 373-378;RunnerTests+Lifecycle.swift:254). - It's cleared only by
targetReset/ a new target PID (RunnerTests+Lifecycle.swift:228, 252), by the 120 s expiring, or by a runner restart. - The thresholds and the duration are
letconstants. No env var, config or CLI flag changes them.preferredBackend(the SDK snapshot option; daemon flag keysnapshotPreferredBackend) does override the plan, even under penalty (RunnerTests+SnapshotCapturePlan.swift:243-255), but the CLIsnapshotcommand doesn't expose it (still true in 0.21.28).
Evidence (runner.log)
- One
SNAPSHOT_XCTEST_CHANNEL_PENALIZED … reason=queries_backend_timeoutwas followed by 70PRIVATE_AX_SNAPSHOT_USEDcaptures in the next ~2 min. - One session's runner.log, covering several days and 43 runner launches, has 273
PENALIZEDlines (196queries_backend_timeout, 72tree_backend_timeout, 5slow_tree_capture_…) against 7PENALTY_CLEARED. All 50 penalties that re-armed inside 120 s aretree_backend_timeout. Most of thequeries_backend_timeoutones come shortly after the previous penalty expired (median about 21 s). 41,053 of 57,766 snapshot commands loggedXCTEST_CHANNEL_DEFERRED. Another session's log has 115PENALIZED(60 / 51 / 4) against 1 cleared.
Related: #1542.
Requests
- Make the slow threshold and the penalty duration configurable (env or CLI / session option).
- Don't penalize the channel for a single 1 s query-sweep timeout alone, and don't let the 1 s recovery probe re-arm the penalty.
- Expose
preferredBackendon the CLIsnapshotcommand (and as a session default), so a client can forcerecursiveTreefor steps that need an accurate, top-most-screen tree. - Optionally, mark private-AX nodes that belong to a covered (non-top-most) presented screen, so clients can filter them out. (0.21.28's
presentedSurfacefact, #3565, may cover part of this; not yet tested on our side.)
Happy to provide more logs or test a nightly.
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 339
- Avg merge
- 11h 59m
- Merged PRs (30d)
- 736
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from callstack/agent-device
-
Limrun iOS fill reports success but drops non-ASCII textPossibly taken @mvanhorn claimed this 1 day ago. Openbug ready-for-agent
Difficulty 2/5 1-3 hours Newbie friendliness 87/100
callstack/agent-device#3819 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
callstack/agent-device#1869 ·
Maintainers usually reply within 1 day
-
iOS: XCTest runner publishes window-relative frames and shifted taps for an iPad app that does not fill the screen (Windowed Apps / Stage Manager)Possibly taken @thymikee claimed this today. Openneeds-triage
Difficulty 4/5 3-5 days Newbie friendliness 20/100
callstack/agent-device#3899 ·
Maintainers usually reply within 1 day
-
iOS 27: `_UIFloatingBarContainerView` still marks content "covered" when the container matches its parent or sits a few points below the viewport topPossibly taken @jonstuebe claimed this today. Openbug
Difficulty 4/5 1-2 days Newbie friendliness 68/100
callstack/agent-device#3883 · 1 comment ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 24/100
callstack/agent-device#3871 ·
Maintainers usually reply within 1 day
All issues in callstack/agent-device
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Automattic/data-liberation-agent#953 ·
Maintainers usually reply within 1 day
-
documentation
Difficulty 1/5 Under an hour Newbie friendliness 90/100
funmary-app/funmary#399 ·
Maintainers usually reply within 1 day
-
area:curator enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
CassioDalla/Scrinalia#150 ·
Maintainers usually reply within 1 day
-
status: needs-triage v1-bug-bash
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
a2ui-project/a2ui#3533 ·
Maintainers usually reply within 1 day
-
backend enhancement priority:P3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
geolens-io/geolens#3310 ·
Maintainers usually reply within 1 day