Repository navigation
feat(ios): route Simulator snapshots through the bridge with bounded fallback #2197
Description
Parent: #2188
Blocked by: #2191, #2196, #2178
Transitive prerequisite: #2177 → #2178.
Stacking requirement: begin from the exact merged #2178 head, or from its exact open head when the
reviewer explicitly requests a stack. Never recreate, modify, or re-export the retired
src/daemon/handlers/interaction-* paths from an older base.
Outcome
Route eligible local iOS Simulator snapshots through #2196's host adapter, present them through
#2191's engine, and preserve the current XCTest runner as a typed, bounded fallback. The route must
never publish a wrong/stale tree, reset the request deadline, or compare captures across incompatible
producer identities.
This issue changes snapshot producer selection but deliberately preserves today's runner prewarm and
open/relaunch waiting behavior. Observation lifecycle optimization belongs to the next child.
Routing policy
- Eligible local iOS Simulator acquisition attempts the bridge first.
- Appium, Limrun, macOS, tvOS, physical iOS, custom actions, and runner-dependent interactions retain
their existing routing unless explicitly covered by their owning issue. - The bridge returns
stage: 'acquired'and always crosses TypeScript geometric presentation. - XCTest returns
stage: 'presented', skips TypeScript geometry exactly once, and still crosses host
invariants and semantic compaction. - No public CLI flag selects the producer. Selection is private Apple runtime policy driven by typed
capabilities and request intent.
Generation and fallback policy
Maintain one circuit state per target generation:
healthy: attempt bridge;degraded: one bounded runner fallback with typed residue;disabled-for-generation: stop retrying the same broken bridge until app/Simulator generation
changes.
Fallback is allowed only for typed qualifying bridge failures or acquisition-invariant violations.
A valid empty presentation is not a fallback condition. Bridge and runner attempts share the
original request's wall-clock deadline; fallback never resets it.
On producer switch:
- invalidate incompatible comparison baselines;
- capture a new baseline under the fallback producer before judging change;
- preserve
full | surface-observationacquisition intent; - require matching producer, intent, generation, presentation key, and compatible residue before
comparison; - structurally pin action-outcome corroboration to
fullusing test(ios): establish snapshot convergence baselines and permanent evidence #2189's deep-button fixture.
Interaction-facade ownership
Any tap-outcome, settled-observation, stabilization, or comparison call-site change must use #2178's
accepted interaction facade and its src/daemon/interaction/internal/ owner. Do not widen the
facade, resurrect old handler paths, or copy comparison policy into the Apple runtime.
Errors and diagnostics
- Preserve typed bridge, fallback, timeout, cancellation, stale-generation, and invariant failures.
- Preserve
hint,diagnosticId,logPath, typeddetails, request id, and previously accumulated
warnings. - Record acquisition and presentation timing separately; neither presentation nor proxy time feeds
the XCTest acquisition penalty breaker. - A comparison re-baseline is diagnostic state, not a successful action verdict.
Non-goals
- No runner-demand policy or removal of runner readiness from open/relaunch.
- No proxy benchmark/acceptance changes, provider migration, physical-device change, custom-action
move, or public backend flag. - Do not remove the XCTest tree/query/private-AX backends, runner manager,
.xctestrunpreparation,
or interaction protocol.
Acceptance and evidence
- A structural test proves acquired bridge output is geometrically presented once and runner output
skips geometry once. - Bridge success, typed failure, invariant failure, valid empty output, timeout, cancellation, crash,
stale generation, and circuit-open paths have closest-negative coverage. - Fallback occurs at most once and remains inside the original deadline.
- Relaunch cannot publish a previous-generation tree.
- Producer switches re-baseline; the deep-button regression proves shallow observation cannot veto a
real full-tree change. - First runner-dependent interaction retains every declared interaction guarantee.
- Matched before/after test(ios): establish snapshot convergence baselines and permanent evidence #2189 measurements show no increase in wrong-tree, stale-tree, unreadable-tree,
or interaction failures. - Focused Apple/runtime, interaction-facade, settle/outcome, structural, XCTest, and affected gates
pass. Record planted-red proof for routing and comparison invariants.
Worker stop conditions
- Stop if refactor(daemon): move interaction and find routes behind the interaction facade #2178 is unmerged and the exact stack head is unavailable; do not patch pre-move paths.
- Stop if a fallback condition depends on error text rather than typed reason/details.
- Stop if any attempt resets the deadline or an empty valid tree activates fallback.
- Stop if physical-device or provider behavior changes.
Activity
thymikee commentedon Sep 5, 2026
The matched acceptance corpus for #2279 is now published separately with an immutable commit, tag
evidence/ios-snapshot/ae26f7afc0.Head
ae26f7afc064c75c65c71e677d32d77cdf2f9709versus base7a2d48d160aaacb582c6f4cde98b6af7531bf7af: six screens × 20 warm captures each per revision, 240 total, zero sample failures or anchor mismatches. The corpus includes public responses, capture-path traces, fixture provenance, checksums, foreground fallback/relaunch proof, native guard-deletion tests, and exact-head CI records. Corpus and checksum verification passed independently after handover.Median/p95 CLI latency is lower on all six screens in this run; uncontrolled host load and sequential sampling mean this is bounded evidence, not a general speed guarantee. #2279's stale pending-evidence wording is removed. Runner-demand/open latency and proxy acceptance remain #2198; no acceptance waiver or merge was performed.