Skip to content

perf: collapse iOS simulator relaunch into one simctl launch call - #1024

Merged
thymikee merged 2 commits into
mainfrom
claude/ios-relaunch-collapse
Jul 2, 2026
Merged

perf: collapse iOS simulator relaunch into one simctl launch call#1024
thymikee merged 2 commits into
mainfrom
claude/ios-relaunch-collapse

Conversation

@thymikee

@thymikee thymikee commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

open --relaunch on a simulator dispatched close (simctl terminate, ~0.7s), settled 300ms, then dispatched open (simctl launch, ~0.8s). simctl launch --terminate-running-process does the whole relaunch in one ~0.94s call, so the simulator fast path skips the close dispatch and the post-close settle.

Steady relaunch: ~2.9s → ~2.0s (iPhone 17 Pro sim, iOS 26.2; best steady sample 1.96s with startup.durationMs 879 — the dispatch itself got slightly longer since terminate now happens inside the launch call, while the total dropped).

Mechanics

  • terminateRunningApp threads from the open dispatch context through Interactor.open to buildIosSimulatorLaunchArgs; only the simulator bundle-id launch path consumes it. Real devices and Android keep the two-step relaunch (their close paths carry teardown semantics).
  • Runtime hints keep working: they are defaults write values read at the next app launch, which the collapsed call still performs — verified the write-while-running ordering in runtime-hints.ts.
  • --clear-app-state keeps the close-first ordering: state clearing must never mutate a running app's container, so that flag opts out of the fast path.
  • The relaunch existing launchIosSimulatorApp retry policy (FBS launch errors) applies unchanged to the collapsed call.

Validation

  • 120 session handler tests pass, including updated expectations (single open dispatch with the flag, one post-open settle) and a new --clear-app-state opt-out test.
  • On-device: 3 relaunches (1.96–3.44s under background load, best-case at the predicted ~2.0s), healthy post-relaunch snapshot and click @ref.
  • typecheck / lint / format / build clean.

open --relaunch on a simulator dispatched close (simctl terminate,
~0.7s), settled 300ms, then dispatched open (simctl launch, ~0.8s).
simctl launch --terminate-running-process does the whole relaunch in one
call (~0.94s), so the fast path skips the close dispatch and the
post-close settle: steady relaunch ~2.9s -> ~2.0s.

The terminateRunningApp option threads from the open context through the
interactor to buildIosSimulatorLaunchArgs; only the simulator bundle-id
launch path consumes it. Runtime hints keep working - they are
user-defaults writes read at the next launch, which the collapsed call
still performs. --clear-app-state keeps the close-first ordering so it
never mutates a running app's container; real devices and Android keep
the two-step relaunch.
@thymikee
thymikee force-pushed the claude/ios-relaunch-collapse branch from 62e4792 to e63d9d9 Compare July 2, 2026 12:28
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.5 MB 1.5 MB +302 B
JS gzip 479.4 kB 479.6 kB +122 B
npm tarball 580.7 kB 580.9 kB +159 B
npm unpacked 2.0 MB 2.0 MB +302 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.5 ms 27.9 ms +0.4 ms
CLI --help 48.9 ms 50.4 ms +1.5 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/session.js +100 B +57 B
dist/src/apps.js +116 B +33 B
dist/src/9722.js +43 B +16 B

@thymikee

thymikee commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Review finding: the collapsed simulator relaunch currently applies to any app-surface open with an open target, including valid open <app> <url> --relaunch requests, but the URL dispatch path does not forward or consume terminateRunningApp (handleOpenCommand's url !== undefined branch calls interactor.open(app, { ..., url }) without the flag, and the simulator explicit-URL path only launches without --terminate-running-process for web URLs/launch args, or just openurls custom deep links). That means the session layer skips the old close dispatch while the platform layer also does not terminate the running app, so URL relaunches lose the relaunch semantics and may fail/stay warm instead of restarting. Please either restrict the collapse to the single app-launch path (for example one positional/no URL) or thread the flag through the URL launch path, with a regression test for open app url --relaunch.

Review finding: open <app> <url> --relaunch reached the collapsed fast
path, but the URL dispatch branch never consumes terminateRunningApp -
a deep-link open never launches the app, so there is nothing to attach
the terminate to. The session layer skipped the close while the platform
layer did not terminate either, silently losing relaunch semantics.

The collapse now applies only to the single app-launch form
(openPositionals.length === 1); URL relaunches keep the explicit
close-then-open sequence, with a regression test.
@thymikee

thymikee commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Fixed in cf90009 — went with the restrict option. The collapse now requires openPositionals.length === 1, so open <app> <url> --relaunch keeps the explicit close-then-open sequence. Threading the flag through the URL path isn't viable for the general case: the custom deep-link branch is simctl openurl only — there is no launch call to attach --terminate-running-process to — so close-first is the only way to honor relaunch semantics there, and splitting web-URL launches onto a different rule than deep links wasn't worth the matrix.

Added the regression test: open app url --relaunch on a simulator asserts ['close:…', 'open:… url'] with no terminateRunningApp in the context. The gate comment now spells out why the URL form is excluded. 121 session tests green.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Jul 2, 2026
@thymikee
thymikee merged commit 6dc0aa5 into main Jul 2, 2026
21 checks passed
@thymikee
thymikee deleted the claude/ios-relaunch-collapse branch July 2, 2026 13:53
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-02 13:53 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