Skip to content

Mobile: unchanged controls can receive taps before a dismissed overlay releases input #1682

Open

Description

@shamilovtim

What happened

A deterministic tap immediately after closing a fading overlay can land on the overlay while e2e reports that the intended underlying button was tapped. The underlying button already exists at the same accessibility bounds, so the unchanged-control shortcut skips the configured transition wait. Existence at unchanged bounds does not establish that the control can receive the touch.

Expected: the framework synchronizes this sequence implicitly. Test code should remain:

await screen.getByRole('button', 'Close overlay').tap();
await screen.getByRole('button', 'Underlying action').tap();

No explicit wait method or additional sleep should be required.

Public native reproduction

App source, commands, reports, native events and all recordings.

  • Unmodified main d8b694ffa48b04c94d70a11cc280267f1ea9a100, after fix(mobile): wait for transitions before screen swipes #1564. Source builds: e2e 0.23.0 / @e2e-dev/mobile 0.12.6; agent-device 0.21.36; Node 24.22.0; iPhone 15 Pro / iOS 27.0.
  • The constructed UIKit composite overlay fades its panel and backdrop for 750 ms while their touch-owning parent remains until animation completion. The underlying button remains exposed to accessibility. This is a custom inline-overlay reproduction; the stock UIKit page-sheet control passes.
  • The 750 ms case fails with transition: 1000 and all three repeats at transition: 2000, with underlying taps 0 / overlay touches 1.
  • Trace step 4 reports a successful underlying tap. The native event log places the overlay touch 283.48 ms after dismissal begins, before completion at +752.70 ms.

Existing upstream work checked

Native readiness investigation and fix direction

The SDK already has an internal native querySelector path that checks XCUIElement.isHittable. A direct diagnostic against the owned runner correctly rejects the unique underlying control while the inline overlay is open and fading, then finds it after animation completion. The ordinary SDK press ignores that result and still sends the intercepted input. The normal public attributes query instead reports geometric hittable: true during the obstruction.

Reuse the existing native predicate inside the SDK's pre-dispatch readiness owner. Wait within the operation budget until the intended target is actionable, preserving target identity and rejecting ambiguity before input. Validate duplicate/anonymous target behavior and benchmark the additional query cost. The native diagnostic establishes the signal for this fixture; generic identity binding still needs implementation and verification.

No public test wait method, private runner access from the e2e adapter, duplicate overlay detector, or blanket adapter delay is proposed. Related SDK coverage work remains in callstack/agent-device#4347.

Supersedes the explicit-wait API proposal in #1563.

Implementation and verification

  • Implicit readiness: agent-device #4391, tracked in #4388, now at e66ec2a063b5fde0ff74609322bee54535003478 on base eec35e9. It uses the shared admission owner, one observation loop/request budget and one evidence construction/copy/remap owner. After a blocked target becomes ready, a fresh canonical capture and new-generation proof precede input. The latest revision also fixes elapsed motion refusals, retains remapped Android evidence and declares readiness intent at the tap owner. No public wait API is added.
  • Pending-request cancellation: #1685, tracked separately in #1684, remains green at d45a6e15 with feedback addressed. It forwards pending-action signals; already-sent input may still finish.

Current source, actual traces and all 23 original recordings cover selector/ref readiness, real default deadlines, caller aborts, motion and readiness in the same loop, and first idle presses. Ten traced SDK cases and four matched comparison cases pass. Nine proof-harness failures and their partial results stay visible. All5,384 video samples decode without errors. Actual native products retain historical build attribution. Caller cancellation remains dispatch unknown despite observed zero target/late input.

The exact local gate passes 15 runnable checks,19,543 unit tests plus three existing skips, and396 related tests. Hosted CI has12 successful checks,two skips,and two failed checks from one iOS Settings replay failure plus its aggregate. Native tests and the actual automated review pass. That replay failure remains under investigation; local27.0 comparisons do not establish a flake on hosted26.2/SDK26.5.

The when-unknown idle-cost proposal and coherent98-file/3,517-gross-line size exception await explicit maintainer disposition. Neither approval nor merge readiness is claimed. Partial-point occlusion remains separate in agent-device #4347.

Historical verification

Historical SDK proof records source c7d640f, its clean exact gate and current native golden-data recheck. The final follow-up changes six test-data fields only; all 629 built JavaScript files and shipped native fingerprint match verified 17a9673. That earlier append retains the fresh production/unit builds, nine passing selected native tests and unchanged-harness overlay video, plus links to matched readiness costs and broader fixture coverage. Every run keeps its original source attribution. Accepted-input ordering evidence records the bounded SDK drain/serialization contract and actual app relaunch behavior, including its limits.

Both implementation PRs remain open. After the SDK fix ships, the consumer dependency can be updated and the original fixture retained as regression coverage.

Activity

  1. okwasniewski commented on Nov 11, 2026

    @okwasniewski
    Member

    Confirmed on main. waitForTransition (packages/mobile/src/surface.ts:1327) skips the transition budget when the control sits at the same bounds as before the last action, and agent-device 0.21.36 does the same (moving-target-gate.ts:120 returns stationary). Same bounds does not mean the control can take a touch, so an inline overlay that keeps input while it fades gets the tap.

    The fix belongs in agent-device's pre-press check (native isHittable, already used on the selector path in RunnerTests+Interaction.swift:205, not on ref presses), so we'll track callstack/agent-device#4388 / #4391 rather than add a wait in e2e. Once it ships we bump the pin and keep your fixture as a regression test. #1644 / #1686 (covered marks) don't cover this case since the overlay carries no covered mark; #1685 handles the cancellation side.

    This was an automated triage.

  2. added
    bugSomething isn't working
    mobileMobile engine (@e2e-dev/mobile)
    agent-deviceRoot cause in agent-device, fixed upstream then bumped here
    P2Improvement / follow-up
    on Nov 11, 2026
  3. shamilovtim commented on Nov 11, 2026

    @shamilovtim
    ContributorAuthor

    Current state:

    [Codex] responding on behalf of @shamilovtim

    • agent-device #4391, 7ab3d23: implicit native press readiness; current CI is green (14 passed, two expected skips), all 37 review threads are resolved, and the latest automated review is clear. The final test/documentation follow-up has byte-identical runtime JavaScript and native inputs to the verified native revision.
    • e2e #1685, e15c058: centralized cancellation for all eight press routes; all 523 mobile tests, local checks, iOS/Android CI and automated review pass.
    • e2e #1690, 82076ff: strengthened existing web timeout assertion; full web suite/checks and CI pass. A half-budget regression passes the old assertion and fails the revised one.

    Current source and regression evidence includes all 17 final native recordings, every failed/setup attempt, full-stream decode receipts and explicit source attribution. Measured 500-control readiness overhead remains 521–597ms versus base; it is not hidden behind a latency-target claim.

    None of these PRs closes the deferred private-AX origin bug agent-device #4399. Ownership and exact PR coverage are recorded there; its separate implementation is under verification and has no PR yet. Healthy placed-window results are not presented as a degraded-origin fix.

    All three linked PRs remain open/unmerged and await maintainer action. No merge, release, or human approval is claimed. The explicit-wait proposal #1563 remains closed; ordinary action calls acquire readiness implicitly.

  4. shamilovtim commented on Nov 11, 2026

    @shamilovtim
    ContributorAuthor

    Current state:

    [Codex] responding on behalf of @shamilovtim

    • Merged: #1690, the independent web timeout assertion fix. Its companion Web timeout test flakes when the remaining budget is below 2000 ms #1689 is closed.
    • Open, current checks passed: #1685 at d45a6e15, pending-press cancellation. All three optional re-review points have dispositions; 524 mobile tests and full repository checks pass, as do iOS/Android deterministic CI and the five-version Node matrix. No new native run is claimed for the test-only follow-up.
    • Open, revision under verification: agent-device #4391, implicit native readiness. The latest large-tree ready-path cost review is being addressed. The maintainer’s text-entry identity proposal was accepted in the recorded decision; fresh native correctness and matched timing results are still required. Earlier measurements are historical.
    • Open, current checks passed: agent-device #4439 at 2c30d54, the separate lost-origin fix for #4399. Fourteen checks passed, two skipped, and all six review threads are resolved. It preserves capture authority and refuses unsafe snapshot-derived coordinate input; it does not implement overlay readiness. Published source, exact checks and linked original recordings.

    The explicit-wait proposal #1563 remains closed. The consumer dependency can be updated after the readiness fix ships; the test call sequence still needs no explicit transition-wait API. Partial-point occlusion remains separate in callstack/agent-device#4347. This umbrella remains open.

  5. shamilovtim commented on Nov 11, 2026

    @shamilovtim
    ContributorAuthor

    Current state:

    [Codex] responding on behalf of @shamilovtim

    • Merged: agent-device #4439 (lost screen origin), e2e #1690 (web timeout assertion) and agent-device #4450 (exited Android recorder). Their issues are closed.
    • Open: agent-device #4391, e66ec2a, addresses the latest architecture/code feedback with fresh traced native evidence. Exact local gate:19,543 unit passes,+3existing skips,396related passes. Hosted CI:12success/2skip/2fail; one Settings replay failure plus its aggregate is under investigation. Native tests pass; actual automated review reports zero issues. Local27.0 passes do not classify hosted26.2/SDK26.5 as a flake.
    • Open: e2e #1685, d45a6e15, feedback addressed and26successful checks/3skips.

    Current immutable evidence and all23neworiginal recordings: ten successful traced SDK cases, four successful comparison cases, nine preserved proof-harness failures;5,384 decoded samples/zeroerrors. Prior6b7/5cda evidence remains historical and unchanged.

    The idle-cost and coherent-size exceptions remain pending explicit maintainer disposition. #1563 stays closed. This umbrella remains open for upstream merges/releases and a later consumer update. Partial-point occlusion remains separate in agent-device #4347.

  6. shamilovtim commented on Nov 13, 2026

    @shamilovtim
    ContributorAuthor

    Current state:

    Next step: complete the remaining SDK live checks and publish their exact source, results and recordings. The native-readiness cost-policy decision remains pending maintainer disposition.

  7. shamilovtim commented on Nov 13, 2026

    @shamilovtim
    ContributorAuthor

    Current state: mobile cancellation #1685 is merged and released in @e2e-dev/mobile 0.12.7; #1690 is merged. SDK screen-origin/recorder fixes callstack/agent-device#4439 and callstack/agent-device#4450 shipped in SDK 0.21.37.

    The remaining implicit native-readiness change, callstack/agent-device#4391, is locally verified at 58d22b1 on cc3b99b. Its exact patch, traces, matched warm comparison and all 22 final recordings are published. All 15 runnable local checks passed (19,830 unit tests, 413 related tests), as did eleven selected native methods and the full current correctness matrix. Settings passed its first attempt with the unobservable local-AX qualification retained.

    GitHub rejected the source branch update because upstream workflow changes exceed the token scope, so that PR still contains older e66ec2a and has no hosted CI for this candidate. Explicit idle-readiness/size disposition in callstack/agent-device#4456 also remains pending. External coverage PR #1644 remains a separate coverage/visibility decision. No merge-ready claim is made for the remaining SDK change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Improvement / follow-upagent-deviceRoot cause in agent-device, fixed upstream then bumped herebugSomething isn't workingmobileMobile engine (@e2e-dev/mobile)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions