What happens
scroll stops moving the scrollable and still reports success with the distance it was asked for. On the SDK 58 fixture's /automation route the content freezes after the first gesture or two, and every later gesture is reported as if it landed:
$ agent-device scroll down 0.75 --session lab
msg: Scrolled down by 0.75 of the viewport (656px) gesture 765 -> 109
automation-press y = 310.7
$ agent-device scroll down 0.75 --session lab
msg: Scrolled down by 0.75 of the viewport (656px) gesture 765 -> 109
automation-press y = not-in-tree
$ agent-device scroll down 0.75 --session lab # and 5 more, both directions
msg: Scrolled down by 0.75 of the viewport (656px) gesture 765 -> 109
… 5 x "scroll up 0.6" left the identifier list byte-identical
The offsets are read out of snapshot --json (automation-press, automation-alert-result, …). Five consecutive scroll up 0.6 calls returned success: true and left every identifier at the same y, with the app frozen mid-page on a ScrollView that has plenty of content above and below.
This is what turns CI red on test-app/ios27-scene-lifecycle: the smoke scenario scrolls up to four times toward automation-longpress and the screen never moves, so the step asserts id="automation-longpress" did not become visible after scrolling (run 35523907559, job 106112615304).
Geometry
Gesture endpoints are centred on the viewport with a span of amount x viewport height, and are never clamped to the resolved scrollable:
| amount |
gesture |
viewport |
| 0.5 |
656 -> 218 |
402x874 |
| 0.6 |
699 -> 175 |
|
| 0.75 |
765 -> 109 |
|
The /automation scrollable is inset from the window:
ScrollView / role=RCTEnhancedScrollView subrole=UIScrollView rect=(18,178,366,662)
so a 0.75 gesture ends at y=109, which is 69pt above the scrollable's own top edge, in the navigation bar. On /catalog the same build reports rect=(18,62,366,729), every amount stays inside it, and scrolling works in both directions.
Why this stayed hidden is inference rather than measurement, and worth checking before a fix is scoped: main's fixture is the same screen on an older Expo/RN whose scroll view is presumably not inset, so the same unclamped formula would keep landing inside and the missing movement check would never be needed to pass CI. I did not measure main's fixture on this route — its app cannot launch on the 27.x runtimes here.
The success answer is the requested distance, not the observed one
Scrolled down by 0.75 of the viewport (656px) is printed while the measured offset is unchanged. The information needed to catch this is already computed elsewhere: scroll top on the same frozen route refuses honestly —
success=false "scroll top moved nothing across 3 passes: the container still re…"
— and the CI request log for the failing smoke run shows the post-gesture comparison accepting a snapshot that equals the pre-gesture one:
post_gesture_snapshot_stale_accept {"action":"scroll","attempts":8,"matchedPreGestureBaseline":true}
post_gesture_snapshot_stabilization_timeout {"action":"scroll","attempts":4,"durationMs":1653}
ios.snapshot-source.acquire {"error":"iOS Simulator snapshot source unsupported: foreground-owner-unverified"}
ios_snapshot_route_fallback {"reason":"target-resolution-failed","error":"Unable to resolve the running iOS Simulator app (simulator-target-dis…"}
A directional scroll that observes matchedPreGestureBaseline: true should not be able to answer with a distance.
Environment
- iPhone 17 simulator, iOS 27.0, also reproduced against the iOS 27.1 CI runner.
- CLI built from
main at 921a2cb3a; no CLI change on the branch — only examples/test-app moves under it (Expo SDK 58 / RN 0.88, whose RCTEnhancedScrollView and inset layouts are what expose the bug).
- Repro:
open com.callstack.agentdevicelab --relaunch --launch-url agent-device-test-app:///automation, wait text "Automation lab", then scroll down 0.75 repeatedly and compare snapshot --json offsets between calls. /catalog is the working control.
Expected
scroll answers with observed movement, and fails with a typed reason when the gesture produced none, instead of echoing the requested amount.
- Gesture endpoints get clamped to the resolved scrollable's frame, so an inset scroll view is still reachable at any
amount.
Related: #2711 (interactions on the Duo's inner panel report success and change nothing, with the same absence of display/coordinate evidence in the request log).
What happens
scrollstops moving the scrollable and still reports success with the distance it was asked for. On the SDK 58 fixture's/automationroute the content freezes after the first gesture or two, and every later gesture is reported as if it landed:The offsets are read out of
snapshot --json(automation-press,automation-alert-result, …). Five consecutivescroll up 0.6calls returnedsuccess: trueand left every identifier at the samey, with the app frozen mid-page on aScrollViewthat has plenty of content above and below.This is what turns CI red on
test-app/ios27-scene-lifecycle: the smoke scenario scrolls up to four times towardautomation-longpressand the screen never moves, so the step assertsid="automation-longpress" did not become visible after scrolling(run 35523907559, job106112615304).Geometry
Gesture endpoints are centred on the viewport with a span of
amount x viewport height, and are never clamped to the resolved scrollable:656 -> 218699 -> 175765 -> 109The
/automationscrollable is inset from the window:so a
0.75gesture ends aty=109, which is 69pt above the scrollable's own top edge, in the navigation bar. On/catalogthe same build reportsrect=(18,62,366,729), every amount stays inside it, and scrolling works in both directions.Why this stayed hidden is inference rather than measurement, and worth checking before a fix is scoped: main's fixture is the same screen on an older Expo/RN whose scroll view is presumably not inset, so the same unclamped formula would keep landing inside and the missing movement check would never be needed to pass CI. I did not measure main's fixture on this route — its app cannot launch on the 27.x runtimes here.
The success answer is the requested distance, not the observed one
Scrolled down by 0.75 of the viewport (656px)is printed while the measured offset is unchanged. The information needed to catch this is already computed elsewhere:scroll topon the same frozen route refuses honestly —— and the CI request log for the failing smoke run shows the post-gesture comparison accepting a snapshot that equals the pre-gesture one:
A directional scroll that observes
matchedPreGestureBaseline: trueshould not be able to answer with a distance.Environment
mainat921a2cb3a; no CLI change on the branch — onlyexamples/test-appmoves under it (Expo SDK 58 / RN 0.88, whoseRCTEnhancedScrollViewand inset layouts are what expose the bug).open com.callstack.agentdevicelab --relaunch --launch-url agent-device-test-app:///automation,wait text "Automation lab", thenscroll down 0.75repeatedly and comparesnapshot --jsonoffsets between calls./catalogis the working control.Expected
scrollanswers with observed movement, and fails with a typed reason when the gesture produced none, instead of echoing the requested amount.amount.Related: #2711 (interactions on the Duo's inner panel report success and change nothing, with the same absence of display/coordinate evidence in the request log).