Skip to content

perf(ios): ask a ready runner about surface hosts before spawning probes - #3877

Merged
thymikee merged 2 commits into
fix/ios-lingering-surface-hostfrom
perf/ios-surface-presence-runner-first
Oct 22, 2026
Merged

thymikee merged 2 commits into
fix/ios-lingering-surface-hostfrom
perf/ios-surface-presence-runner-first

Conversation

@thymikee

@thymikee thymikee commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

Summary

Stacked on #3873; retarget to main once it merges.

Every iOS simulator capture ran the host-side system-surface probe first: two pgrep -f spawns plus ps environment reads. That costs 50–150 ms per capture, and --settle makes 2–3 captures. Since #3873, a ready runner's read of every registered host's XCUIApplication.state decides the route anyway, and it answers in a few milliseconds.

The route now asks a ready runner first:

  • Every host off screen: stay on the bridge, with no process probe.
  • A foreground host: take the runner route with that host.
  • No ready runner, or a failed read: run today's process probe.

#3873's later refinement step is gone, since a present from the probe now only arrives when the runner could not answer. The ADR 0004 paragraph is updated.

4 files.

Validation

  • pnpm check:affected --run --head d2dcc82027: passed.
  • New route tests fail at fix(ios): keep the bridge while a surface host only lingers #3873's head 10bc49d00e, 3 of 4 cases.
  • Live, Bluesky 1.136.0 (real account, SafariViewService lingering), iOS 27.0 simulator, 6× snapshot -i, daemon request time:
    • base 10bc49d00e: 194–316 ms (median ~281), 2 pgrep + 4 ps spawns per capture.
    • head d2dcc82027: 110–142 ms (median ~117), 0 pgrep, 3 ps (target resolution).

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

Every simulator capture ran the host-side system-surface probe, two
pgrep -f spawns plus ps reads, about 50-100ms per capture and two or three
captures per settled press. A ready runner answers the same question
from XCUIApplication.state of every registered host in a few
milliseconds, and its answer decides the route since #3873. Ask it first,
and run the process probe only when no runner is ready or the read fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thymikee
thymikee added this pull request to stack #3878 October 21, 2026 18:48
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.51 MB 5.51 MB -85 B
Package (unpacked) 5.51 MB 5.51 MB -85 B
Package (download) 1.67 MB 1.67 MB -42 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.9 ms 26.6 ms -1.3 ms
CLI --help 51.7 ms 51.5 ms -0.1 ms

Review follow-up: a probe that cannot answer sends the capture to the
runner, not to the bridge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thymikee

Copy link
Copy Markdown
Member Author

Independent review (Codex, read-only) of d2dcc82027: no code findings. One P3 docs finding is fixed in 8ad34e6db3: ADR 0004 now names all three process-probe outcomes (running → runner, not running → bridge, cannot answer → runner with system-surface-probe-unavailable). pnpm check:affected --run --head 8ad34e6db3: passed.

@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 8ad34e6. The code looks right, and all 16 reported checks pass. No conflicts.

Not blocking, and you can take or leave these. The runner read in snapshot-route.ts (https://github.com/callstack/agent-device/blob/8ad34e6/packages/platform-apple/src/snapshot-route.ts#L129) now runs on every eligible simulator capture, before the bridge-disabled check and before any host process exists. If the runner reports ready but does not answer, a capture can wait up to the 1s read timeout. The removed test in snapshot-route.test.ts also pinned that a disabled generation never pays the foreground reads, and the new order drops that. A short note in the ADR or PR body would cover both, or you could skip the read after a recent failed read for the device. Could the runner-first, probe-second composition move into one presence resolver beside the two probes, so the route makes one call that returns present, absent or unknown? That would also let you trim the long comment above the capture path.

I did not run a live device or simulator, so the performance numbers and the "few milliseconds" read latency are unverified. I did not read the runner recovery or transport timeout path in depth, so whether a timed-out read leaves the session intact rests on the #3873 design. I confirmed the test regression claim by reading the code, not by running the tests at the base commit.

Merge once #3873 lands and this PR is retargeted to main.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 21, 2026
@thymikee
thymikee merged commit 9058aac into main Oct 22, 2026
16 checks passed
@thymikee
thymikee deleted the perf/ios-surface-presence-runner-first branch October 22, 2026 03:06
@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-22 03:07 UTC

thymikee added a commit that referenced this pull request Oct 22, 2026
* origin/main:
  feat(test-app): add a Bluesky-depth heavy feed screen (#3884)
  fix(android): read a child that vanished mid-read as gone (#3901)
  feat(ios): route iPad Simulator snapshots through the host AX bridge (#3895)
  Prepare shared resource ownership and selection for #3325 (#3887)
  refactor(kernel): track held execution locks in keyed-lock (#3879)
  perf(ios): ask a ready runner about surface hosts before spawning probes (#3877)
  fix(ios): keep the bridge while a surface host only lingers (#3873)
  perf(ios): synthesize taps on resolved in-app back controls (#3880)
  fix(macos): open a running app by its own path instead of its bundle id (#3889)
  fix(macos): accept mixed-case bundle ids in open (#3867)
  fix(macos-helper): scroll SwiftUI forms whose rows are scroll-area children (#3888)
thymikee added a commit that referenced this pull request Oct 22, 2026
* origin/main:
  fix(android): read a child that vanished mid-read as gone (#3901)
  feat(ios): route iPad Simulator snapshots through the host AX bridge (#3895)
  Prepare shared resource ownership and selection for #3325 (#3887)
  refactor(kernel): track held execution locks in keyed-lock (#3879)
  perf(ios): ask a ready runner about surface hosts before spawning probes (#3877)
  fix(ios): keep the bridge while a surface host only lingers (#3873)
  perf(ios): synthesize taps on resolved in-app back controls (#3880)
  fix(macos): open a running app by its own path instead of its bundle id (#3889)
  fix(macos): accept mixed-case bundle ids in open (#3867)
  fix(macos-helper): scroll SwiftUI forms whose rows are scroll-area children (#3888)
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