fix(ios): serve regular --depth from every snapshot backend - #2431
Conversation
A regular depth-capped request was refused on every runner backend but the recursive tree: the query sweep past depth 1 and private AX at any depth returned no capture, so a plan pinned or deferred to private AX (custom actions, a private AX verdict on the session, the XCTest channel penalty) fell through to the synthetic sparse root, which the daemon then rejected as "regular iOS snapshot presentation requires a valid viewport". Presentation already applies the presented-depth cut to whatever hierarchy a backend acquired, and a depth-capped regular capture is a subset of the unscoped one from the same backend, so the refusal protected nothing the unscoped answer did not already disclose through truncated/effectiveDepth. Delete the gate, declare private AX as regular-depth=presentation-cut, and record the rule in ADR 0004. Closes #2403
Size Report
Startup median (7 runs, lower is better):
|
|
The fix looks sound at bb3dfdc, and the reported simulator reproduction plus CI are green. One regression test is still needed: RegularDepthTests calls presentation directly, so it passes even with the old runner backend refusal restored. Add a runner-path test for private AX pinned with regular --depth that reaches acquisition and presentation rather than the sparse fallback, and show that restoring the deleted gate makes it fail. |
…ugh acquisition The presentation-package test passes with the old backend depth gate restored, because it calls presentation directly. This runner-bundle test pins private AX, asks for regular depth 1 against the launched host app, and requires the plan to reach acquisition and presentation: a private-ax verdict that is not sparse, more than one node, a real root rect, and a payload no larger than the unscoped capture from the same backend. With the gate restored the plan logs SNAPSHOT_BACKEND_DEPTH_UNSUPPORTED and returns the zero-rect sparse root, and the test fails.
|
Added in 1db684c: It launches the host app with Green at 1db684c (iOS 26.2 Simulator, Red with the gate restored ( i.e. exactly the synthetic sparse root the daemon then rejects as a missing viewport.
|
|
The runner-path regression at 1db684c addresses the remaining review gap. It exercises private AX acquisition and presentation, and the reported simulator red/green run shows that restoring the old gate produces the sparse-root failure. No remaining code findings; ready for human review while CI finishes. |
|
Summary
Closes #2403.
On 0.21.0 every
is <selector> visible --depth <n>on the reporter's iOS Simulator failed withregular iOS snapshot presentation requires a valid viewport. The cause is in the runner, not the daemon:SnapshotBackendKind.canServeRegularPresentedDepth(from #1947) refused a regular depth-capped request on private AX at any depth and on the query sweep past depth 1. Whenever the plan is pinned or deferred to private AX (custom actions, a private AX verdict already on the session, the XCTest channel penalty), no backend could serve, the plan fell through to its synthetic sparse root (oneApplicationnode, zero rect), and the daemon rejected that root as a missing viewport.Presentation already applies the presented-depth cut to whatever hierarchy a backend acquired, and a depth-capped regular capture is a subset of the unscoped one from the same backend, so the refusal protected nothing that
truncated/effectiveDepthdid not already disclose. This PR deletes the gate, declares private AX asregular-depth=presentation-cut(fixture, TS registry, Swift enum, all parity-tested), rewrites the ADR 0004 paragraph that made the old claim, and adds a presentation test for the cut on a hierarchy acquired past the frontier.8 files touched. Not changed here: a genuine sparse runner verdict (no backend could read the screen) still surfaces as the viewport-invariant error instead of the runner's own "use screenshot" message; that is a separate daemon-side seam.
Validation
Tested commit:
bb3dfdc8a2b8627d5f16adb423c4a18ddef1af50.snapshot --depth 20 --actionsreturned the runner's sparse payload (state: sparse, one zero-rectApplicationnode) and the daemon failed with the reported message; plain--actionsworked.snapshot --depth 20 --actionsreturns 58 nodes;--depth 1 --actionsreturns 4. Through the test-ownedsnapshotPreferredBackend: 'private-ax'transport seam:snapshot --depth 20is a 58-noderecoveredprivate AX capture,is visible role=button label=Generalpasses at depth 20 and 3, and depth 0 returns the correctSelector did not match.testPrivateAXPinnedRegularDepthReachesAcquisitionAndPresentation(PR iOS lane): green at 1db684c in 4.9 s; red with the gate restored (5 assertions, runner logsSNAPSHOT_BACKEND_DEPTH_UNSUPPORTED backend=private-ax depth=1). Evidence in the review reply.AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS=1, iOS 26.2 sim):testSnapshotBackendDeclarationsMatchCapabilityFixture,testSparsePayloadReasonMatrix,testLegacyQualityMessageStatesFallbackMeaningpass (3 executed).swift test --package-path apple/snapshot-presentation: 3 tests pass, including the newRegularDepthTests.pnpm check:affected --run: green on bb3dfdc (387 files, 2827 tests). On 1db684c the vitest-related stage hit 7 contention timeouts on a Mac at load 125; those five files pass in isolation (68/68) and the delta is Swift test code plus one workflow line;check:xctest-selectionpasses.Risk: the physical-device plan now also lets the query sweep answer a
--depth ≥ 2request with its flat sweep (same payload it already returned unscoped) instead of no answer.