Repository navigation
fix: never pin a HID transport auto-selected inside the boot-attach window - #72
Conversation
…indow dtuhidd attaches 0-3 s after boot on a simulator booted while Device Hub is open, so upstream's transport auto-selection races it: a HID verb landing inside the window picks Indigo, the connection is cached under the boot token, and the wrong transport is silently pinned for the entire boot (Indigo reports success without delivering, so recovery never fires). Gate the cache instead of the construction: a connection whose transport was auto-selected while launchd_sim uptime is under 15 s is served to the command that created it but never reused, so the next command re-derives the selection after the attach window closes. This is the issue's skip-the-cache variant, implemented as cache-but-don't-reuse so every connection stays on the explicit disconnect path. A forced SIM_USE_HID_TRANSPORT selection cannot race and is cached unconditionally; an unknowable launchd_sim identity keeps the marker-fallback caching behavior. Also wire the diagnostics prerequisite: SIM_USE_DEBUG=1 turns on the default logger's stderr sink so the transport-selection signals are visible in normal runs and in the daemon logfile. Fixes #67 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rir4WwrPShf5DYzziJ8RyC Signed-off-by: onevcat <onevcat@gmail.com>
Live verification (Xcode 27 Beta 4, Device Hub)Contrary to the "live reproduction is limited" caveat in the PR body, the race was reproduced live on this branch, and the fix held. With Device Hub open, The losing selection was made, was not cached, and the very same command converged to DTUHID. (This round hit the loud dead-transport variant, which Daemon-mode chain also verified on a fresh boot (8 taps through the window, then 2 past it): Environment notes: on this machine dtuhidd attaches in <1 s (faster than the 0–3 s measured on 07-24), so only a cold in-process invocation races it; and Device Hub's device view did not re-attach across subsequent shutdown/boot cycles (rounds 2–3 stayed dtuhidd-free — consistent with the 07-24 observation that the poisoned state needs the device view attached; in that state legacy Indigo is genuinely functional and taps deliver). |
Review follow-up: the env check lived only in SimUseLogger's no-arg initializer, so `ios batch` - which passes its own flags via SimUseLogger(writeToStdErr: verbose) - ignored SIM_USE_DEBUG entirely and the transport-selection diagnostics stayed invisible without --verbose. OR-merge the env switch inside the parameterized convenience initializer instead: one implementation covers every construction path, batch needs no change, and --verbose keeps its exact behavior. The env predicate takes an injectable environment for tests, which lock the SIM_USE_NO_DAEMON-style "literal 1 only" convention. Verified live: SIM_USE_DEBUG=1 sim-use ios batch --step "sleep 0.1" (no --verbose) now emits the diagnostic info-lines on stderr; without the env var stderr stays quiet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rir4WwrPShf5DYzziJ8RyC Signed-off-by: onevcat <onevcat@gmail.com>
Fixes #67.
Problem
Since the idb bump (#68), the HID transport is resolved by upstream's auto-selection at
FBSimulatorHIDconstruction: DTUHID whendtuhiddlives in the simulator'slaunchd_simsubtree, legacy Indigo otherwise. Butdtuhiddattaches 0–3 s after boot on a simulator booted while Device Hub is open, so a HID verb landing inside that window probes the process tree too early, picks Indigo, and the cached connection pins the wrong transport for the entire boot —typeexits 0 while delivering nothing, and since Indigo reports success,HIDPerformRecoverynever fires. Real risk forsimctl boot && sim-use typescripts and agents.Fix
The issue's skip-the-cache variant, implemented as cache-but-don't-reuse so every connection stays on the explicit
disconnect()path (a truly uncached connection would leak its mach port in the long-lived daemon):HIDBootIdentity.isTransportSelectionTrustworthy(token:now:)withtransportTrustWindow = 15 s(the retired tap family silently no-ops on Device-Hub-poisoned simulators — extend the dtuhidd guard to all HID verbs with a boot-attach criterion #60 guard's window;launchd_sim'sstartedAtis already in the boot token, so no new probe).HIDInteractor.CachedConnectioncarriestransportTrusted; an entry created inside the window serves the command that created it but is discarded (disconnect + rebuild) by the next command, so the selection is re-derived once the attach window closes. Convergence: one command after the window.SIM_USE_HID_TRANSPORTselection cannot race and is cached unconditionally; an unknowablelaunchd_simidentity keeps the pre-existing marker-fallback caching behavior (the race evidence only exists where the probe works).Diagnostics prerequisite
SIM_USE_DEBUG=1turns on the default logger's stderr sink (with debug-level detail), making the transport-selection signal lines visible in normal runs and — since the daemon redirects stderr to its logfile — in/tmp/sim-use-<uid>/<UDID>.log. Same daemon-environment caveat asSIM_USE_HID_TRANSPORT, noted in README.Testing
HIDBootIdentity.isTransportSelectionTrustworthysuite was written against a stub reproducing today's always-cache behavior and failed on exactly the three new-behavior assertions (inside-window ×2, future start time) before the real implementation went in.make buildandmake testgreen (1161 tests).🤖 Generated with Claude Code
https://claude.ai/code/session_01Rir4WwrPShf5DYzziJ8RyC