Skip to content

iOS: taps and scrolls on a foldable's lit inner panel report success and do nothing #2711

Closed

Description

@thymikee

What happens

On the iPhone Duo simulator in the open pose, tap and scroll against the app running on the inner panel report success while the UI does not change at all. Snapshot state confirms nothing moved: the tab bar keeps [selected] on Home after a reported tap on Catalog, and a reported scroll down leaves the next capture pixel-identical.

Reproduction

Device: iPhone Duo simulator, iOS 27.1, pose open (operator action), Xcode 27.1 beta. App: examples/test-app Release build at 5eb509d21.

agent-device open "Agent Device Tester" --platform ios --udid <duo> --session duo1
agent-device snapshot --session duo1     # @e37 [button] "Home" [selected], @e39 [button] "Catalog"
agent-device tap @e39 --session duo1     # Tapped @e39 (205, 903)
agent-device snapshot --session duo1     # Home still [selected]
agent-device scroll down --session duo1  # Scrolled down
agent-device screenshot --session duo1   # identical bytes-in-content to the previous capture

The tap point is on target

Capture is the inner panel at 951x669 @1x with currentOrientation: rot90. Mapping the reported app-space point (205, 903) through that panel's mapping (visual_x = app_y, visual_y = 669 - app_x) lands on visual (903, 464), which is the center of the Catalog icon in the captured image. Ref resolution and geometry agree with what is on screen; the injection simply has no effect.

Control: the same binary responds everywhere else

  • iPad Pro 13-inch (M5), iOS 27.1: tap on the same Catalog tab item navigated to the catalog, and Catalog became [selected].
  • iPhone 17, iOS 27.0, portrait and landscape: normal.

So this belongs to the second/foldable panel, not to the native tab bar or to the app.

Relationship to #2703

#2703 taught capture to select the lit panel. Interaction dispatch does not appear to share that notion: it reports success for an injection aimed at a surface that is not the one being captured. xcrun simctl io <duo> screenshot captures the inner panel at 2853x2007 showing the app content, so the app's scene really is on the panel that receives no touches.

Please classify this path in packages/contracts/src/interaction-guarantees.ts against the native implementation: either the session binds its interaction root to the lit panel, or the call fails with a typed reason instead of returning success for input that cannot land. A silent no-op is the worst of the available outcomes, because it reads as a passing interaction and then the next assertion fails for a reason the log cannot explain.

Activity

  1. thymikee commented on Sep 20, 2026

    @thymikee
    MemberAuthor

    Two facts that should narrow the hunt, both measured after filing.

    It is not the native tab bar, and it is not the app. The same Release binary on iPad Pro 13-inch (1032pt) and iPhone 17 (874pt landscape) selects the Catalog tab on tap and reports the new [selected] state in the next snapshot. On the Duo's inner panel the identical ref resolves, reports the tap, and changes nothing.

    The no-op leaves no trace. I went looking for the injection target in the session diagnostics and the runner log:

    • sessions/<session>/requests/*.ndjson for the tap and scroll requests contain no display, panel, LCD/LCD-1, or orientation field.
    • sessions/<session>/runner.log is the xcodebuild test-without-building transcript; the only lines matching tap|touch|display are the two command lines themselves.

    So the failure mode is doubly silent: the command returns success, and no log says which surface the event was aimed at. Whatever the fix is, the interaction path should record the display it resolved for the injection — on a device family whose whole point is that two surfaces disagree about which is live, "which panel did you touch" is the first question a triager asks and today the answer is nowhere.

    Control I could not run: the same device in the closed pose, which would separate "rot90 inner panel" from "iPhone Duo in general". Both Duo simulators on this host are in the open pose and folding is an operator action, so that datum needs a human at the simulator.

  2. thymikee commented on Sep 20, 2026

    @thymikee
    MemberAuthor

    Possible sibling: #2714. There scroll also answers with the requested distance while the measured offset never changes, on a plain iPhone rather than the Duo's inner panel, and the request log there shows the post-gesture snapshot being accepted while identical to the pre-gesture one (post_gesture_snapshot_stale_accept, matchedPreGestureBaseline: true). Worth checking whether the Duo case resolves to the same accepted-stale-snapshot path or really is a wrong-display dispatch, because the two need different owners.

  3. thymikee commented on Oct 8, 2026

    @thymikee
    MemberAuthor

    Verified fixed on main bf2246499 (fixed by #2724, which routes gestures to the lit panel's display). iPhone Duo simulator, iOS 27.1, fold open (LCD-1, 669x951pt panel, captured 951x669), Safari:

    • press @e8 on the address field: Tapped @e8 (475, 48). The field took focus and type "example.org" entered the text with suggestions shown.
    • press on the "Example Domain" suggestion row: Tapped @e7 (476, 114). Safari navigated to example.org.
    • scroll down: the page moved, and the before and after screenshots differ (content scrolled by about 160 px).

    The closed-pose control wasn't needed because the open pose now works.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions