Skip to content

Apple platform + runner: simplify, shrink, and preserve correctness (tracking) #2803

Description

@thymikee

Apple runner: simplify, shrink, and preserve correctness

This initiative removes unnecessary Apple runner/platform-apple production code while preserving device-proven behavior. Correctness and regression proof come first; abstractions must earn their cost by removing decisions, state or mechanisms. Cleaner file layout alone is not success.

Source baseline: 5712a3552e209c9c853bc1f42cb3e007f1213139, including #2911 isolation and #2961 placeholder propagation. GitHub main 8c89891b215c8504d1881eef06031d1d5f223726 was also checked: its SDK exports do not alter these implementation scopes. Every executor must check drift before editing. Findings here are source-verified; this audit did not rerun simulators or physical devices.

Core success criterion: less production machinery

This is part of #2803's simplify-and-shrink initiative. Before production simplification, name the production mechanism, duplicated decision, state, fallback, forwarding layer, or public/internal interface this change removes. Compare deletion and inlining against extraction. Moving the same state into another file is not a deletion case.

Every PR reports baseline/final SHAs; added, deleted and net production lines; test/fixture/documentation changes separately; and the exact mechanisms removed. Use a rename-aware diff (git diff --numstat -M BASE...HEAD) and account for all affected production paths, including destination packages. Moving tests out of production files, generated output, formatting churn, and moving code elsewhere are not production-code deletion. Preserve readable code; no compressed formatting to hit a number.

Default for simplification work: net production reduction. A required behavior-preserving size split may be line-neutral. Growth needs an explicit, quantified explanation of the correctness or type guarantee it buys, why deletion/inlining cannot achieve it, and what old mechanism is removed; it is not automatically acceptable because ownership looks cleaner. If the only benefit is relocating fields or adding a wrapper, defer the change. Required regression tests and a minimal correctness fix are allowed to grow without inventing unrelated deletion to offset them.

The initiative must report its cumulative production delta and the mechanisms actually eliminated. Separate correctness/type-safety growth from cleanup savings; the cleanup tranche should shrink. A positive overall production delta is not “simplify-and-shrink complete” without an explicit maintainer decision to rescope the goal. Historical removals before this follow-through baseline do not count as new savings. Do not set an arbitrary deletion quota before measurement, and do not delete necessary recovery just to make the total negative.

Architecture constraints

Keep one host session/resource owner and one accounting owner. Separate command exchange only enough to satisfy the owning-module and size rules. Keep the existing main-actor target state; preserve distinct native-work, penalty, warmup and private-AX lifetimes. Shared native-build mechanics should shed snapshot-specific dependencies. Swift/TypeScript presenters retain shared semantic proof. No new actor, retry, cache, or generic service framework is part of this initiative; an actor experiment must independently demonstrate a deletion/coordination benefit before becoming implementation work.

The earlier concrete scheduler and penalty extractions are retained as deferred candidates, not required end-state modules.

Execution order and status

Verified 2026-09-25: #2911 is merged; #2963 remains open. This tracking update does not merge either PR. Complete/rebase overlapping host cleanup onto #2963's exact merged head (or explicitly declare a stack on its published head); do not block independent classification/tests on unrelated host files.

Order Work Gate / success
1 Finish the in-flight deletion in #2963; preserve merged #2911 Establish the overlapping host baseline; do not redo landed isolation work
2 #2965 accounting model and correctness fix Decide command-identity settlement, then smallest fix; minimal required size extraction only
3 #2972 typed AX; #2974 differential; #2970 native-build seam Delete redundant classification/plumbing; add decisive regression proof; native-build move needs an actual deletion case
4 #2967 session/exchange split → #2971 payload types Required split targets neutral/negative lines; type-safety growth reported as such
5 #2968 characterization → conditional #2969 Characterization must establish a real gap or deletable repeated logic before ownership migration
Deferred #2966 scheduler owner; #2973 penalty owner No implementation until redundant state/coordination can be deleted or a concrete correctness need is shown
Measurement track Outer transport resend; private AX; #2662 curl verdict Establish whether larger paths can be removed; keep or delete based on working control evidence

Run shared runner Swift work (#2966/#2968/#2969/#2972/#2973, and any overlapping native harness edits) one issue at a time, rebasing after each merge. Disjoint TS/test research may proceed independently; devices and full host gates remain exclusive. Do not infer scheduling readiness from an old paragraph or an unchecked box: child labels and the scope gates above must agree.

Measure before deleting: explicit workstream

These are research deliverables, not authorization to remove fallbacks speculatively. A measured “retain” result is valid and must name the concrete capability/failure it still serves.

  1. Outer read-only transport resend. Owner: this umbrella, packages/platform-apple/src/runner/runner-client.ts. Current source distinguishes three transport attempts from eight RUNNER_BUSY attempts; do not treat them as one redundant loop. Trace which lower layer already retries/recycles, prove both paths reachable, and compare transport retries enabled versus a one-attempt experimental control. Record command IDs, native execution count, transport send count, final outcome, elapsed budget and cancellation behavior for initial connection failure, recoverable post-send loss, startup failure, busy/draining and stale-session recovery. Use the existing fake-runner wiring plus simulator/physical lanes relevant to the claimed removal. Deliver a retain/delete/narrow verdict, exact production paths/lines removable and required regression cases. Coordinate A wait timeout during runner start stops the runner, so the retry pays the start again #2894/ios(runner): a 1 s readiness preflight abandons a busy runner command and the next connect stalls behind it, failing waits on cold hosts #2475; do not silently reduce the busy drain window or replay mutations. Temporary diagnostics must be removed or justified as an owning diagnostic.
  2. Runner private-AX tier. Owner: this umbrella, with ADR 0004 and iOS: skip private-AX deep extension on observation-only captures (settle, stabilization, corroboration) #1626 as related existing work. Inventory which consumers still require custom actions, unavailable/disabled host bridge, occupied XCTest recovery, raw/depth semantics, real-device/provider support and differing quality/viewport facts. Prove the proposed substitute actually serves each required case with matching fidelity and budget before any deletion. Include bridge-circuit-open and hostile-screen controls; a success on the healthy simulator path is insufficient. Deliver a capability/evidence matrix, retain/delete/partial-reduction verdict, net implementation delta including any new bridge features, and precise unsupported cases. The earlier ~1.4k-line estimate is historical, not a guaranteed saving; count current reachable code. Do not expand iOS: skip private-AX deep extension on observation-only captures (settle, stabilization, corroboration) #1626's shallow-acquisition task into tier removal.
  3. Curl-through-simctl verdict. Existing owner refactor(ios-runner): one response decoder, a session state enum, and a verdict on the curl-through-simctl transport #2662, remaining task 3. Preserve its diagnostic/history investigation, but require positive control evidence for reachability and the original failure condition; “no fallback seen” on an unexercised route is insufficient. Report which simulator-set/toolchain/network condition needs it, or a concrete deletion patch scope including its encoder and tests. Preserve refactor(ios): point xcodebuild at the scoped simulator set and delete the XCTestDevices redirect #2963 scoped-set behavior and existing timeout/cancellation semantics. Keep this work under refactor(ios-runner): one response decoder, a session state enum, and a verdict on the curl-through-simctl transport #2662 rather than create a duplicate transport issue.

Each research result is recorded here or on its named owner with baseline SHA, conditions, artifacts, counterexample coverage, and deletable production scope. Any implementation decision becomes a bounded child contract before coding; a research result alone does not change a device support guarantee.

Before/after scorecard

Every implementation PR records its baseline SHA, final SHA, actual commands/results, and the following applicable measures:

Dimension Before Required after
Behavioral correctness Existing successes plus each named gap Existing suite remains green; bug/proof work includes a demonstrated failing case or planted policy mutation
Ownership Direct state writers and mixed responsibilities listed in child One authoritative writer/transition seam; no mirrored registry, counters, compatibility facade, or public mutable cache
Contract strength Optional payload bag / prose-based inference / hidden test exclusions Negative type or classification cases rejected; new differential arms actually execute
Change locality List concrete files needed for one representative policy change Policy and its tests colocated; callers express intent without reconstructing ordering or reset subsets
Code removed Record production additions/deletions/net delta and old mechanisms Cleanup shrinks; mandatory splits may be neutral; correctness/type growth explicitly justified; no moved-code savings
Code structure Record touched-module/test line counts Source and matching tests split together where required; no new >1,000-line files or forwarding-only layers
Runtime behavior Matched fixture outputs, retry counts, transport sends, busy/handoff and cache outcomes Exact preservation except #2965's accounting correction and #2972's code-only AX classification correction; genuine native AX paths retain their outcome; unchanged deadlines, fallback order and wire omissions
Performance No new measurements were collected by this audit No claimed speedup; investigate any observed regression with matched device, toolchain, backend and fidelity

For a suspected timing regression, use scripts/ios-snapshot-benchmark/README.md: at least 10 matched cold/first-interaction samples and 20 warm/relaunch samples, retaining raw results and backend/quality facts. These sample counts support comparison, not a universal latency promise or a new invented percentage threshold. Do not demand device timing for a type-only or pure-classification change.

Fresh worktrees require pnpm install --frozen-lockfile && pnpm build. Follow docs/agents/testing.md, docs/agents/device-verification.md, and each child's focused checks; run pnpm check:affected --run on the final diff. Stage new files before trusting tracked-file layering gates. Do not hide a module split with eager-closure allowlists or bulk Fallow baseline regeneration. Selected native/device lanes are obligations; distinguish local fake-runner proof, simulator proof, and physical-device proof. Mark unavailable device evidence pending.

Existing owners, preservation rules, and exclusions

  • Apple runner: make off-main access to main-owned capture state fail the runner gates (RunnerMainOwnedState) #2882 owns static main-actor enforcement. Keep the already-landed RunnerMainOwnedState isolation and compile canary; coordinate new owner files with its remaining source guards.
  • refactor(ios-runner): one response decoder, a session state enum, and a verdict on the curl-through-simctl transport #2662 already delivered response decoding and the session-state enum. Its remaining curl verdict is part of the measurement workstream above; its public dispatch-outcome discussion stays separate.
  • Make snapshot membership loss attributable: scroll clip authority + ejection dispositions #2754 remains the owner of broader membership attribution/ejection dispositions and capture surveys. The linked differential child owns only its still-missing runner-stage proof.
  • Preserve independent launch/retry/recorded-failure traits, shared synthesized tap fallback, reported/derived/missing viewport facts, deadline-exhausted capture disqualification, and physical-iOS relaunch retention.
  • Keep native main-thread occupancy distinct from host command completion. Terminal journal status is not proof that abandoned native work has drained.
  • Keep target transition reset subsets distinct until characterization proves otherwise. In particular process refresh rearms warmup; external relaunch currently does not.
  • Keep the Swift bundle-and-expiry XCTest penalty, private-AX accepted-depth cache, warmup exemption, and host app-generation bridge circuit separate.
  • Screenshot/recording helpers presently located in RunnerTests+Lifecycle.swift are an opportunistic colocation step inside the target-transition child only when needed to isolate that owner. No standalone file-shuffling project.
  • Do not replace both snapshot presenters with one universal engine, rewrite the entire runner to actors/async, invent a generic retry/circuit-breaker framework, delete private-AX/curl fallbacks without measurement, or expand protocol/device support.

Non-blocking actor follow-up

#2976 compares a command-control actor with an equivalent concrete synchronized coordinator after the first cleanup wave (#2963, #2965, #2972, #2974, #2970). It requires preserved ordering/timeout behavior and a measured deletion/complexity case. It does not block this umbrella's completion and does not authorize a production actor migration. Run the experiment before reconsidering the deferred scheduler/penalty extractions or expanding target ownership; keep shared Swift edits serial. A negative result is a valid completion.

Closure

Close only after checking active child states and merged PRs, reporting the cumulative production delta and removed mechanisms, and recording retain/delete decisions for the measurement track. Deferred #2966/#2973 and conditional #2969 do not force low-value implementation: explicitly retain their deferral or close them with rationale after review. A positive production delta requires an explicit scope decision rather than a shrinkage claim. A design gate is not complete merely because it was written down.


Historical audit

Purpose

A tracking issue for a simplification and correctness audit of the Apple side: packages/platform-apple (about 32k lines of production TS) and apple/runner (about 17.5k lines of Swift plus ObjC bridges), at 01328de411.

Method:

  1. Four read-only audits applied community Swift skills: AvdLee and twostraws Swift Concurrency and Swift Testing, the Swift API Design Guidelines, and jazzychad's ios-code-audit.
  2. A second model cross-reviewed every finding against the code.
  3. The top claims were spot-checked by hand.

Findings refuted in review are not filed here.

Verdict: the core machinery earns its complexity: runner lifecycle, lease detach/adopt, recycle ledger, readiness preflight, command journal, three-tier snapshot plan, and the private-AX ladder pinned by conformance fixtures. The waste sits at the edges. Removing it cuts about 1–1.5k production lines, and moving the inline tests (#2792) takes about 3.9k lines out of production Swift files.

Each child issue is one PR (or a small series of pure-move PRs) inside one module group.

Original audit status (verified 2026-09-25)

The three previously outstanding issues are now closed: #2788 / #2865, #2796 / #2858, and #2797 / #2876. All three PRs are merged. The prior audit's checklists follow; these are historical results, not new improvement measurements.

Bugs (original audit)

Cuts (ready-for-agent)

Decided 2026-09-23 (codex cross-check + code verification), now ready-for-agent

Already tracked elsewhere

#2662 (still open) covers runner-session cleanup: the response decoder, a state enum, and the curl-through-simctl transport.

Historical measurement candidates (now promoted above)

  • The outer 3× read-only retry in runner/runner-client.ts:42-56. It predates the recycle ledger (Runner resilience under agent-abuse command patterns #1105).
  • The runner's private-AX tier, about 1.4k lines. It could go only if the host bridge learns to read custom actions, and removing it weakens recovery while the bridge circuit is open.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions