Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

refactor(ios-runner): one response decoder, a session state enum, and a verdict on the curl-through-simctl transport

Closed
#2,662 2 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
45/100
Issue type
Refactor
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript

Research direction

Start with packages/platform-apple/src/runner/runner-session.ts, runner-command-recovery.ts, and runner-adoption.ts, then run the named recovery and adoption suites to trace the three response-decoding paths. Work through the cuts in order; done means the stated grep checks, affected/layering/export checks, simulator and macOS lanes, and the required session-transition tests pass without changing timeout values.

Written by the indexing model from the issue text.

Description

ready-for-agent refactor

Remaining scope in the deletion-first initiative

#2803 now includes task 3 (the curl-through-simctl verdict) in its measurement workstream. The decoder/state-enum work has already landed; do not repeat it from the historical descriptions below.

Before deleting postCommandViaSimulator, establish that the control route is reachable and reproduce or explicitly account for the original failure condition. A week with no fallback observations is insufficient if the relevant simulator-set/toolchain/network condition was never exercised. Record baseline SHA, route selection, successful primary/fallback controls, timeout/cancellation outcomes, and a retain/delete verdict. Preserve #2963's scoped simulator-set behavior; coordinate overlapping edits with that PR. If retained, name the actual condition and evidence. If deleted, report all removed production paths/encoders and the net production-line delta, with tests separate. Temporary instrumentation is removed or justified as an owning diagnostic.

The public dispatch-outcome discussion remains outside this cleanup scope. Historical task descriptions follow.


Why

The largest maintenance surface on the Apple platform is not geometry, it is the daemon-side cluster that babysits the XCTest runner process: packages/platform-apple/src/runner/ is 38 production files, about 10k lines. A survey on main at 91652a8fc5 found the following (file:line refer to that head):

  • Three response decoders for one wire. parseRunnerResponsePayload in runner-session.ts:973 (the canonical one), parseLifecycleResponsePayload in runner-command-recovery.ts:353 (the status recovery probe), and an inline JSON.parse in runner-adoption.ts:140 (the uptime probe).
  • Four command-encode paths. runner-transport.ts:48 (sendRunnerCommandOnce, host TCP / usbmux), runner-usbmux.ts:52 (raw HTTP framing over the usbmux socket), runner-startup-transport.ts:371 (tryRunnerEndpoints, the startup connect probe) and runner-startup-transport.ts:418 (postCommandViaSimulator: simctl spawn <udid> /usr/bin/curl …, a shell-out inside the Simulator, still reachable from lines 119 and 400).
  • Six notions of "alive". isRunnerProcessAlive / isRunnerProcessTreeAlive / runnerSessionsStillAlive in runner-disposal.ts:274/269/177; hasLiveIosRunnerSession in runner-client.ts:192 reading getRunnerSessionSnapshot in runner-session.ts:442; probeRunnerAnswersUptime in runner-adoption.ts:127 (wire-level); and canSkipRunnerReadinessPreflightAfterHealthyMutation in runner-command-traits.ts:56, a separate "healthy enough to skip the preflight" axis.
  • No runner state. RunnerSession (runner-session-types.ts) has no state field, only booleans (ready, computed alive, lastHealthyMutation); the readiness-preflight decision in runner-session.ts:87–101 and the cache decision in runner-cache.ts:450–462 are string-literal unions that stand in for one.
  • 29 timeout/budget constants across 12 files (runner-startup-transport.ts:36–40, runner-disposal.ts:26–33, runner-session.ts:78–81, runner-lease.ts:23–25, runner-device-set.ts:18–20, runner-sequence.ts:24–35, and single constants in six more files).

None of this is a bug. It is where the next incident will take longest to diagnose, and it is the code a contributor has to read to touch anything about runner startup.

Task

Three bounded cuts, each its own PR, in this order. Do not attempt a rewrite.

  1. One response decoder. Make parseRunnerResponse (runner-session.ts) the only place a runner response body is decoded; have the recovery status probe and the adoption uptime probe call it (or a narrower function it exports) and delete the two private decoders. Tests: runner-command-recovery and runner-adoption suites keep their current expectations; add one test per probe proving a malformed body is rejected the same way the main path rejects it.
  2. A session state enum. Add state: 'starting' | 'ready' | 'draining' | 'stopped' (adjust names to what the code actually distinguishes; derive from the existing booleans and the readiness-preflight reasons, do not invent states) to RunnerSession, with one transition function. Replace the six "alive" checks with two: process liveness (OS fact, host.ts) and session state. hasLiveIosRunnerSession becomes a state read. The readiness-preflight decision keeps its reason codes (they are diagnostics), but the decision reads state plus lastHealthyMutation. Any SessionState-like field added to a persisted record follows the R7/R10 rule in CONTEXT.md (owner entry plus schema bump).
  3. Retire postCommandViaSimulator if it is dead. Establish first whether the curl-through-simctl path ever answers where the host TCP and usbmux paths do not, after usbmux became primary (#1403). Instrument with a diagnostic (ios_runner_startup_transport phase, which transport answered) and read it over the iOS simulator lanes and the nightly (.github/workflows/xctest-nightly.yml) for a week, or find the commit that introduced it and the failure it worked around. If no run needs it, delete it together with its encode path; if one does, document the condition next to the function and close this sub-task.

Acceptance criteria

  • After (1): grep -rn 'JSON.parse' packages/platform-apple/src/runner/*.ts (production files) shows exactly one site; pnpm check:affected --run green.
  • After (2): RunnerSession has a state field; grep -rn 'alive' packages/platform-apple/src/runner/*.ts shows only the process-liveness primitive and reads of state; the daemon device status output for a running iOS session is unchanged (compare JSON against main); the iOS simulator integration lane and the macOS host lane green; one recorded startup, one idle-stop and one recycle each transition through the enum, asserted in runner-session tests.
  • After (3): either the function and its encode path are gone and the startup transport tests are updated, or a comment above it names the concrete condition it serves with the run that proved it.
  • No timeout value changes in any of the three PRs (the constants are a smell, not a target; changing them changes startup timing, which #2324/#2325 calibrated).
  • The layering check (pnpm check:layering) and pnpm check:production-exports stay green; no new exports from packages/platform-apple/src/runner/index.ts.

Non-goals

Merging or renaming files for their own sake. Changing lease, cache or xctestrun-artifact logic (runner-lease.ts, runner-cache*.ts, runner-artifact*.ts): those are a different cluster with their own invariants (#2598). Reducing the number of timeout constants.

Related: #1403 (usbmux primary), #2324 / #2325 (startup budget), #2598 (process lock), ADR 0005 (runner interaction lifecycle), ADR 0019 (request-bound platform runtime).

Dominant language
TypeScript
Stars
4.8k
Forks
315
Avg merge
11h 17m
Merged PRs (30d)
536

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from callstack/agent-device

All issues in callstack/agent-device

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.