Skip to content

Commit 0e9b731

Browse files
committed
fix(ios): restore two-phase stabilization and the rebased plan-state switch
Takeover of #1573 on top of #1587. - The rebase onto main merged textually but not semantically: #1587 turned the plan-state -> pre-seeded first-failure mapping into an exhaustive switch, and this branch's new `.preferredIndependentBackend` case was never added to it. Counterfactual: without the added case the runner does not compile ("switch must be exhaustive", RunnerTests+SnapshotCapturePlan.swift:159). - That switch and `countsAsRecovery` were two independent encodings of the same question — did this plan state degrade the capture. They had to agree, or the runner could stamp a `recovered` verdict with no reason to render. Dropped `countsAsRecovery` and derived the recovered flag from the single mapping, so a future state cannot satisfy one and not the other. - Reapplied b113f17's reviewed two-phase stabilization refactor, which the earlier rebase silently dropped (412 -> 377 LOC, no flag-driven orchestration). Behavior is unchanged; the two budgets are modeled as the two sequential phases they actually are. - Documented the freshness-probe reorder on `effectiveSnapshotCapturePlan`, and replaced the normal-path comment that contradicted the change under it: the available-tier filter is not a fallback-attribution change for its own sake, it stops the all-tiers-failed stamp from naming a simulator-only backend on a physical device.
1 parent d8d3574 commit 0e9b731

2 files changed

Lines changed: 168 additions & 196 deletions

File tree

apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,6 @@ enum SnapshotXCTestChannelPlanState: Equatable {
5757
case preferredIndependentBackend
5858
case deferredToIndependentBackend
5959
case boundedXCTestProbe
60-
61-
var countsAsRecovery: Bool {
62-
switch self {
63-
case .normal, .preferredIndependentBackend:
64-
return false
65-
case .deferredToIndependentBackend, .boundedXCTestProbe:
66-
return true
67-
}
68-
}
6960
}
7061

7162
struct EffectiveSnapshotCapturePlan {
@@ -154,16 +145,19 @@ extension RunnerTests {
154145
return pending
155146
}
156147

157-
/// The pre-seeded first-failure a penalized plan stamps into its verdict. The deferred case
158-
/// uses the dedicated 'deferred' code: the breaker pre-selected the backend, nothing new
159-
/// degraded on this capture, and the daemon keys warning suppression and the settle budget
160-
/// reset off exactly that distinction. The bounded probe keeps 'budget': its short XCTest
161-
/// slice genuinely constrains what this capture could read.
148+
/// The pre-seeded first-failure a penalized plan stamps into its verdict, and the single
149+
/// source for whether a plan state degraded this capture at all: a nil result is exactly the
150+
/// set of states whose first tier still counts as healthy. The deferred case uses the
151+
/// dedicated 'deferred' code: the breaker pre-selected the backend, nothing new degraded on
152+
/// this capture, and the daemon keys warning suppression and the settle budget reset off
153+
/// exactly that distinction. The bounded probe keeps 'budget': its short XCTest slice
154+
/// genuinely constrains what this capture could read. The freshness probe reorders a healthy
155+
/// plan by request, so like `.normal` it degrades nothing.
162156
static func xcTestChannelStateFirstFailure(
163157
_ state: SnapshotXCTestChannelPlanState
164158
) -> (reason: String, code: String)? {
165159
switch state {
166-
case .normal:
160+
case .normal, .preferredIndependentBackend:
167161
return nil
168162
case .deferredToIndependentBackend:
169163
return (
@@ -181,6 +175,12 @@ extension RunnerTests {
181175
/// Pure plan-reorder rule: a penalized XCTest accessibility channel uses independent backends
182176
/// when the platform has one, otherwise it keeps XCTest work on a short probe. The raw
183177
/// diagnostic plan keeps tree-first errors, and unknown plans are left untouched.
178+
///
179+
/// `preferIndependentBackend` is the daemon's post-gesture freshness probe (#1569): it moves
180+
/// the independent tier first while KEEPING the XCTest tiers as recovery, because the caller
181+
/// wants a backend XCTest cannot serve stale, not a narrower plan. It is strictly weaker than
182+
/// the penalty — a penalized channel still drops XCTest tiers outright — and it is a no-op
183+
/// where no independent backend exists, so physical devices keep their ordinary plan.
184184
static func effectiveSnapshotCapturePlan(
185185
_ plan: [SnapshotBackendKind],
186186
xCTestChannelPenalized: Bool,
@@ -219,7 +219,10 @@ extension RunnerTests {
219219
treeCaptureSliceBudgetOverride: nil
220220
)
221221
}
222-
// Preserve the ordinary plan after removing tiers unavailable on the current platform.
222+
// The ordinary plan, minus tiers this platform cannot serve — the same filtering the
223+
// penalized branches above already do. A tier that is compiled out returns nil anyway, so
224+
// this changes no capture; it only stops the all-tiers-failed fallback from stamping a
225+
// backend that never ran (physical devices attributed `private-ax`, which is simulator-only).
223226
return EffectiveSnapshotCapturePlan(
224227
plan: availablePlan,
225228
xCTestChannelState: .normal,
@@ -261,7 +264,8 @@ extension RunnerTests {
261264
preferIndependentBackend: options.preferIndependentBackend
262265
)
263266
let effectivePlan = effective.plan
264-
firstFailure = Self.xcTestChannelStateFirstFailure(effective.xCTestChannelState)
267+
let planStateFailure = Self.xcTestChannelStateFirstFailure(effective.xCTestChannelState)
268+
firstFailure = planStateFailure
265269
switch effective.xCTestChannelState {
266270
case .normal:
267271
break
@@ -349,7 +353,7 @@ extension RunnerTests {
349353
continue
350354
}
351355

352-
let recovered = kind != effectivePlan.first || effective.xCTestChannelState.countsAsRecovery
356+
let recovered = kind != effectivePlan.first || planStateFailure != nil
353357
if recovered {
354358
NSLog(
355359
"AGENT_DEVICE_RUNNER_SNAPSHOT_RECOVERED backend=%@ reason=%@",
@@ -695,6 +699,9 @@ extension RunnerTests {
695699

696700
func testXCTestChannelStateFirstFailureStampsDeferredCodeOnlyForDeferral() {
697701
XCTAssertNil(Self.xcTestChannelStateFirstFailure(.normal))
702+
// Also the recovered/healthy discriminator: a requested freshness reorder degrades nothing,
703+
// so its first tier must stamp `healthy` exactly like an unmodified plan.
704+
XCTAssertNil(Self.xcTestChannelStateFirstFailure(.preferredIndependentBackend))
698705
XCTAssertEqual(Self.xcTestChannelStateFirstFailure(.deferredToIndependentBackend)?.code, "deferred")
699706
XCTAssertEqual(Self.xcTestChannelStateFirstFailure(.boundedXCTestProbe)?.code, "budget")
700707
}

0 commit comments

Comments
 (0)