You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Prefer the unique booted iOS simulator that contains the requested app when open has no explicit device selector.
Return actionable errors instead of silently falling back to name ordering when zero or multiple simulators match.
Validation
Automated: focused resolver/platform/open tests, lint, typecheck, build, Fallow, provider integration, and serial reruns of parallel timeout cases.
Review — fix: select iOS simulator by installed app
Reviewed the full diff plus surrounding resolution code. This is a clean, well-scoped fix. Recommend merge with a couple of optional nits below.
What it does
When open <app> has no explicit device selector and 2+ iOS simulators are booted, it probes each booted sim for the requested app and selects the unique match. Zero matches → actionable APP_NOT_INSTALLED; multiple matches → AMBIGUOUS_MATCH with a --udid hint. Previously resolveDevice silently picked the alphabetically-first booted sim (src/kernel/device.ts:291-293), so this replaces a silent wrong-device pick with a correct pick or a clear error.
Strengths
Tightly scoped blast radius.findBootedAppleSimulatorWithApp bails early (bootedSimulators.length < 2 → undefined) before any simctl call, so the common single-sim path is untouched and pays zero extra cost. Explicit selectors and lease-backed resolution (allowLocalSimulatorFallback === false) also short-circuit. Good instinct given the perf sensitivity here.
Correct new lookup semantics.findIosSimulatorInstalledApp deliberately does not reuse resolveIosApp's bundle-id pass-through — it verifies the bundle id is actually installed. The doc comment earns its place by explaining exactly that difference.
The cache-key change is the subtle-but-right part. Stripping appleSimulatorAppTarget from the key means the app-aware pick made at open time is reused by every later resolution in the request scope, then pinned via session.device for follow-up commands. That's why the app target only needs to be threaded at the single open call site rather than all ~12 resolveTargetDevice callers. The invariant is documented and covered by the "reuses an app-aware selection" test.
Conventions followed: lazy import('../platforms/apple/core/apps.ts') mirrors the existing findBootableIosSimulator pattern; registered error codes; kernel matchesDeviceSelector/isIosFamily reused rather than re-implemented; distinct candidate lists per error branch (all booted sims for not-installed vs. only matches for ambiguous) is a nice touch.
Test coverage is thorough: unique-match, cache reuse, zero-match, ambiguous, explicit-selector-skips-probe, plus a focused unit test for findIosSimulatorInstalledApp (bundle id, alias, stopped-sim no-probe).
Minor / optional
Option name vs. usage (naming nit).session-open.ts passes appleSimulatorAppTarget unconditionally, so on an Android open the call reads resolveTargetDevice({ platform: 'android' }, { appleSimulatorAppTarget: 'Demo' }) (as the updated runtime test now asserts). It's a harmless no-op since only the Apple path reads it, but the apple-prefixed name on an Android call is mildly confusing. Consider a platform-neutral openAppTarget, or only passing it for Apple platforms.
Latent ordering assumption. The cache-key stripping is correct becauseopen performs the app-aware resolution first in its scope. If a future code path resolved a device earlier in the same scope without an app target, it would poison the cache and the later app-aware call would reuse the wrong sim. Worth a one-line note on the assumption, but not actionable now.
Bare-domain edge (very low risk). A positional like open example.com isn't a deep link, so with 2+ booted sims it'd be probed as a bundle id and surface APP_NOT_INSTALLED. Not worth guarding unless it comes up — open targets are bundle-id / app-name / deep-link in practice.
Complexity is appropriate — nothing over-engineered. LGTM. 👍
P1 — The fresh open route bypasses the app-aware selection.runRequestWithinScope opens the target-resolution cache before createRequestExecutionScope; the latter calls resolveRequestExecutionLockKeys, whose advisory fresh-open path first performs a generic resolveTargetDevice(bindingReq.flags). Because this PR removes appleSimulatorAppTarget from the cache key, handleOpenCommand later receives that generic cached simulator and never reaches findBootedAppleSimulatorWithApp. With two booted simulators and the app only on the second, the motivating failure therefore remains.
Please make the cache/order preserve app-aware selection on the real request route and add a regression that covers generic advisory resolution before app-aware resolution—preferably through fresh open request binding. After the code fix, also provide live two-simulator evidence with the app installed on only one; the current PR documents none.
Re-reviewed exact head 4583bf5: the P1 is fixed. Advisory lock selection and handleOpenCommand now use the same app-target options, so the first request-cache entry is app-aware and dispatch correctly reuses it. The fresh-open regression is non-vacuous: reverting either call site produces a generic first resolution and fails the asserted app-aware binding. Existing resolver tests cover unique, absent, and ambiguous matches. I found no remaining code issue, and all reported checks are green.
Readiness still needs practical evidence: please run a fresh open with two booted iOS simulators where the requested app is installed on only one, and show that the session binds to that simulator. The current tests mock resolution/simctl and do not replace the required live proof. No ready-for-human label yet.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Prefer the unique booted iOS simulator that contains the requested app when
openhas no explicit device selector.Return actionable errors instead of silently falling back to name ordering when zero or multiple simulators match.
Validation
Automated: focused resolver/platform/open tests, lint, typecheck, build, Fallow, provider integration, and serial reruns of parallel timeout cases.