fix(ios): report the real failure reason on a tree-pinned capture terminal
Summary
A regular iOS snapshot pinned to the XCTest tree backend (internal snapshotPreferredBackend, used by the perf evidence probe) on a screen whose tree rejects with the #758 kAXErrorIllegalArgument signature ended sparse while reporting snapshotQuality.reasonCode: requested-backend. The plan seeded the pin decision into its first-failure slot, so the real tier failure never replaced it: callers read a hostile-screen rejection as "pin honored, nothing degraded", and the host's viewport refusal hid the typed reason.
The pin's answer now travels in its own slot. A tier that actually failed owns the verdict reason on failing terminals; an accepted payload still reports requested-backend (what snapshot-forced-tree reads as proof the pin was honored). The breaker's deferred/budget seeds keep their established contract. Touched files: 2 Swift files (runner classifier + in-bundle tests). No scope expansion; unpinned, raw, and private-AX-pin behavior unchanged.
Validation
Head 3dad2ba9fb (base f3d2619abe).
pnpm check:affected --run --head 3dad2ba9fb…: all runnable checks passed,exactCommit=true(receiptrun-hayMl1); device/native lanes GitHub-authoritative.- New Swift in-bundle tests: red on base (
requested-backend≠ax-rejected), green at head; 5 adjacent plan/pin/penalty tests pass;pnpm check:xctest-selectionclean. - Live on iPhone-17-Pro simulator (fixture app, heavy feed), same forced-backend command:
- base: pinned-tree regular → sparse/tree/
requested-backend(bug) - head: pinned-tree regular → sparse/tree/
ax-rejectedwith the real kAXErrorIllegalArgument reason - unpinned regular healthy (95 nodes) and pinned-tree raw unchanged both sides.
- base: pinned-tree regular → sparse/tree/
Unresolved risk: none known; CI device lanes confirm.
🤖 Generated with Claude Code