Skip to content

Wait for a late screen change instead of failing the perf probe run - #204

Closed
arun279 wants to merge 4 commits into
feat/expo-nativefrom
probe/late-change
Closed

arun279 wants to merge 4 commits into
feat/expo-nativefrom
probe/late-change

Conversation

@arun279

@arun279 arun279 commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Why

The iOS perf probe failed its own runs with "no responseMs, doneMs": in run 39878809507 (pass 1, the change app's show detail push), in 39867496265 (pass 2, show detail push), and twice on the first tab switch (39857698481, 39737186653).

I went through the raw videos and the fake Trakt log. In each case the app had acknowledged the command, but the screen did not change within the 2.5 s window.

  • Show detail push, 39878809507:
    • the recording has a single frame, and simctl recordVideo writes a frame only when the screen changes;
    • show detail's requests (seasons, related, fanart) reached the fake Trakt server before the next segment's, so the screen had mounted;
    • the next segment's recording is still on Up Next for 1.5 s, then Up Next's header snaps into place, show detail slides in, and the episode sheet opens on top;
    • that late push landed in the episode sheet's window. It is that segment's 1210 ms response and 2276 ms finish, the maximums in that run.
  • Tab switch, 39857698481: the tab bar moved to Library at once, but the content stayed on Up Next for the whole window.

The probe decided whether anything had happened by looking for a scene change anywhere on screen. A frozen screen has none, and the tab bar's change is below the threshold, so both runs failed as "the probe missed it" instead of being recorded as a late change.

What changes

  • The probe takes a screenshot just before each command.
  • If the content region has not changed by the end of the window, the probe polls screenshots until the content differs from that one, for up to 15 s, before it starts the next interaction.
    • Content that changed late is recorded as censored (>2500), as a late change already was.
    • The late change can no longer land in the next interaction's window.
    • Content that never changes still fails the run.
  • The whole-screen scene pass is gone. Each segment is analysed before the next starts, because the decision to wait depends on the result; that costs about 0.3 s of ffmpeg per segment.
  • A launch that never reports ready now leaves launch-timeout.png, so a stopped run shows what was on screen.

The screenshot digest covers only the content region's pixels, so the status bar clock does not count as a change.

Tests

  • afterWindow censors content that changed only after the window, keeps it empty when it never changed, and leaves measured times alone without waiting.
  • waitForChange resolves once the content differs, and gives up at the limit.

Four mutations each fail a test: always censoring, ignoring measured times, an inverted comparison, and reporting a change on timeout. The screenshots, recordings and the wiring in measure() run only against a device, so they are checked by probe runs rather than unit tests.

Verification

On iOS the screen sometimes does not change for longer than the 2.5 s
window after the app has run a command. In run 39878809507 the show detail
push recorded a single frame, and show detail only slid in 1.5 s into the
next segment's recording, which inflated that segment's time. In run
39857698481 the tab bar moved to Library but the content stayed on Up Next
for the whole window. The probe decided that nothing had happened by
looking for a change anywhere on screen. A frozen screen has none, and the
tab bar change was too small to count, so both runs failed.

The probe now takes a screenshot just before each command. If the content
has not changed by the end of the window, it polls screenshots until the
content differs from that one, for up to 15 s, before the next
interaction. A change that arrives late is recorded as censored (">2500"),
as a late change already was, and can no longer land in the next window.
Content that never changes still fails the run.

Each segment is now analysed before the next starts, since the decision to
wait depends on it. The whole-screen scene pass is gone.
The Android probe in run 39886057572 stopped when the change app's fifth
launch never reported ready within 120 s. Logcat shows the app starting
and its JavaScript running, then no requests to the fake Trakt server or
the probe channel. Nothing showed what was on screen. The probe now saves
launch-timeout.png before it stops.
…e-change

# Conflicts:
#	scripts/perf-probe.mjs
…e-change

# Conflicts:
#	scripts/perf-probe.mjs
@github-actions

Copy link
Copy Markdown

Pull request footprint

measurement base to head
Product code lines in core/src, native/src, native/app, and native/modules +0
Test lines in test, packages/*/{test,__tests__,e2e}, and .maestro +40
CI and tooling lines in .github and scripts +48
Product comment lines identified by a comment prefix +0

User-delivered artifact sizes

measurement base head delta
Expo iOS JavaScript bundle, raw file 5.45 MB 5.45 MB 0 B
Expo Android JavaScript bundle, raw file 5.48 MB 5.48 MB 0 B
Firebase tester APK, arm64-v8a and all densities 41.17 MB 41.17 MB 0 B
Play download estimate, XXXHDPI arm64-v8a English Android 15 19.83 MB 19.83 MB 0 B

Most complex product function

measurement base head
Cyclomatic complexity, oxlint complexity 10 10
Cognitive complexity, Biome noExcessiveCognitiveComplexity 15 15

@arun279

arun279 commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #212, which removes the perf probe from CI along with the rest of the custom device-lane machinery.

@arun279 arun279 closed this Oct 23, 2026
@arun279
arun279 deleted the probe/late-change branch October 23, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant