refactor(ios): give each snapshot capture step its penalty authority
Summary
Refactor #3 from the iOS snapshot-performance plan, following #3896 and #3916. Each capture step now carries its own penalty authority: a new SnapshotCaptureStep (an enum over .ordinary(backend) / .boundedRecovery(backend, claimsPeriodicProbe:)) is built once by the plan factory and travels inside SnapshotBackendAttempt. The penalty recorder reads the attempt's step instead of a re-derived plan position plus a defaulted .normal channel-state argument — the seam that made #3896's probe self-renewal reachable is now unrepresentable. All XCTest-channel policy owners (penalty value, plan reorder, verdict reasons, evidence gates) move to one file, RunnerTests+SnapshotChannelPolicy.swift, whose plan construction is a single site. Behavior-preserving.
Touched files: 6 (3 production, 3 tests). No scope expansion, no interface added.
Production lines (three files, wc -l): 1057 → 1053 vs main. SnapshotCapturePlan.swift 872→630, SnapshotTiming.swift 185→143, new SnapshotChannelPolicy.swift 280. Comments net −13; the 5-line code delta replaces the removed defaulted argument and duplicated evidence gate with the step enum's payload.
Validation
Tested SHA 1e39504de9 (prior SHAs 0ae929c0ea carried the full validation below; the later commits only consolidate plan construction and trim comments). pnpm check:affected --run --head passed (receipt .tmp/validation/run-GPl9i8/receipt.json; iOS/macOS Swift lanes GitHub-authoritative). Full macOS host unit lane: 356 passed, TEST EXECUTE SUCCEEDED. 13 focused iOS-lane tests passed on a dedicated simulator. Historical red/green: the new regression test fails at 1e7092c09a^ (tree_backend_timeout renewal) and passes at head. Four mutations (drop recovery mode, omit probe claim, sweep-added step, post-response probe) each fail an existing test; the guards remain structurally present after the consolidation. pnpm check:xctest-selection and check:packaged-runner-swift pass.
Live on an owned simulator with the production runner: hostile captures armed PENALIZED, deferred plans stamped DEFERRED, the due capture claimed RECOVERY_PROBE inside the plan and did not renew the penalty, and the next ordinary probe re-armed only from its own hostile evidence (queries_backend_timeout).
Independent review of the full range found no blockers; findings were fixed across f873db3629..1e39504de9 (probe claim bound to XCTest-backed steps at construction, single plan-construction site, constraint-only comments).
CI obligations: Apple Smoke / iOS Conformance / Runner Full XCTest lanes are authoritative for the Swift suites.
🤖 Generated with Claude Code