Skip to content

test(ios): recover the E2E visibility search from a scroll that overshoots its target - #2883

Merged
thymikee merged 1 commit into
mainfrom
fix/ios-scroll-overshoot-longpress
Sep 24, 2026
Merged

thymikee merged 1 commit into
mainfrom
fix/ios-scroll-overshoot-longpress

Conversation

@thymikee

@thymikee thymikee commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes the smoke:automation-input flake id="automation-longpress" did not become visible after scrolling (20 CI failures, 09-14..23; #2491).

Mechanism (iOS 26.2 simulator, host CPU load): a controlled scroll down 0.75 (656 pt finger path) sometimes releases with inertia. Screen-recording frame tracking shows the eased drag, then a ~420 pt/s deceleration tail. Content moved 711–852 pt instead of 439–505 pt (6 of 80 scrolls under load). A fling can carry the one-row target past the viewport, and the forward-only search cannot recover.

This is within the documented contract (ADR 0013, scroll help: reduced momentum, no exact offset). Two runner release-tail variants failed: stationary tail samples changed nothing, and a creeping tail made every scroll fling. So the E2E search changes:

  • 3× scroll down 0.75 (reach 2.25 viewports, unchanged), then 3× scroll up 0.5. A reverse step plus a measured fling (≤504 pt) stays inside the visible band.
  • An unsettledGesture read gets a 1 s pause before the re-read.

2 files, test-only. #2864 renames unsettledGesture, which touches one line here.

Validation

At f6afa0103b, with a 36-thread CPU load:

  • 30/30 assertAutomationInput passes (24 on the behavior-equivalent parent, 6 on the head). One run hit the exact CI shape (unsettled probe, failed re-read, misses to the bottom). Two reverse scrolls recovered it.
  • Pre-fix, same load: 24/24 scenario passes. The skip reproduced per scroll: 1 of 40 first scrolls lost the target.
  • Killed mutations: forward-only plan, no pause, two-scroll reach, 0.75 reverse step.
  • pnpm check:affected --run passed.

…hoots its target

A controlled iOS scroll can still release with inertia when the host is
loaded: the app misses the slow tail of the eased drag and UIKit flings
with a mid-drag velocity (~420 pt/s measured), so one scroll down 0.75
moved content 719-852 pt instead of 439-505 pt and carried the one-row
automation-longpress target past the viewport. The forward-only search
then had nowhere to go (#2491).

The search now follows three forward scrolls (2.25 viewports, unchanged)
with three shorter reverse scrolls, whose travel plus a measured fling
stays inside one viewport, and gives a surface the read reports as
unsettled a bounded pause before re-reading it instead of re-reading at
once.
@github-actions

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.80 MB 4.79 MB -6.6 kB
Package (unpacked) 4.80 MB 4.79 MB -6.6 kB
Package (download) 1.44 MB 1.43 MB -1.7 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.0 ms 26.7 ms -0.3 ms
CLI --help 77.8 ms 78.3 ms +0.4 ms

@thymikee

Copy link
Copy Markdown
Member Author

Adversarial review: clean.

Two notes for later:

Merge order with #2864: whoever lands second maps only postGestureOutcome.kind === 'unsettled' to the settle-and-re-read path in live-assertions.ts. no-effect is a real read and must not trigger a settle.

@thymikee

Copy link
Copy Markdown
Member Author

Reviewed at f6afa01. The change stays inside the two files behind the iOS smoke:automation-input scenario from #2491, and all 18 checks pass on this commit, including that smoke lane. I traced the new overshoot test by hand: with a forward-only plan it would fail, so it covers the reverse sweep for real. No blocking issues found.

I did not re-run the live iOS validation; I rely on the reported 30/30 on-device pass and the green smoke job.

One question for later: when #2864 renames unsettledGesture to postGestureOutcome, I see two places here that need the new name, the check in unreadSurface() and the UNSETTLED fixture in the test. Is there any other place that should change with it?

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 24, 2026
@thymikee
thymikee merged commit fe2ac00 into main Sep 24, 2026
18 checks passed
@thymikee
thymikee deleted the fix/ios-scroll-overshoot-longpress branch September 24, 2026 11:40
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-24 11:40 UTC

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

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant