fix(ios): deliver simulator edge swipes as screen-edge touches

GR
11m ago
+834-24

Summary

On iOS simulators, gesture swipe left-edge/right-edge never started edge recognizers or the navigation edge pop: XCTest touches carry no edge information, even at x = 0.

Edge presets now plan a screen-edge contact (contactOrigin). On an iOS simulator, the runner sends that plan as one HID contact the way a hand swipe arrives: SwipeLocked plus the native swipe direction on every frame, through the oldest touchscreen service of the app's display (the lit panel on a foldable). The contact eases in along the planned path, because a first move that leaves the edge region in one frame fails the recognizer on a wide panel.

  • Terminal event: the contact owner builds a cancel event before touch-down. After touch-down, every exit sends the touch-up or that cancel, stamped at dispatch. A cancel that cannot be built stops the command before anything is sent.
  • Reported schedule: the runner execution policy resolves the contact and its schedule together and returns executionProfile (edge-ease-in for this path). gestureResponseData keeps a reported schedule and infers the planned profile only when a backend reports none. ADR 0013 records edge-ease-in and that rule. Plans still cannot request it.

Other gestures and physical devices keep their paths. 23 files. Fixes #4208.

Validation

Tested at 70bb84f7b, base 035c2b6ca.

  • pnpm check:affected --run --head 70bb84f7b: passed, exactCommit=true.
  • Swift unit tests (13, AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS=1, iOS 26.4) include HID constructor failures at each frame. Without the cancel dispatch, the move/lift failure test fails.
  • Repro ./repro.sh, three edge cases plus in-page swipe and pan controls:
SimulatorBaseHead
iPhone 16, iOS 26.40/3 edge5/5
iPhone 18 Pro, iOS 27.2—5/5
iPhone Duo, iOS 27.1, open0/3 edge5/5
iPhone Duo, iOS 27.1, closed—5/5
  • --json timing: right-edge → edge-ease-in, swipe right → endpoint-hold, pan → timed-pan.
  • An injected cancel delivers touchesCancelled, and the next touch begins normally.

Open risk: physical devices are unchanged and untested.