You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Spike: targeted AX invalidation after AX-free gestures (escape hatch for baseline-distrust cap) #1560
Follow-up to #1542 defect 2's approved fix (baseline-comparison distrust in post-gesture stabilization). The v1 fix accepts the result when the bounded distrust cap expires with the signature still matching the pre-gesture baseline — correct for genuine no-op gestures, but it leaves one theoretical hole (a tree that is stale AND partially different reads as settled) and pays a small latency tax on no-op gestures.
Spike question (runner-side, iOS): does a cheap, targeted AX re-resolution hook exist (public or via the private-AX surface the runner already uses for bulk snapshots) that forces the next snapshot query to bypass the cached tree after an AX-free synthesized gesture?
Constraints from history: forced FULL re-resolution on deep RN trees can cost seconds (the #758 sparse-tree/depth-ladder arc and the recurring slow-AX deferrals) — an unconditional post-gesture resync would be a worse agent experience than the bounded cap. The hook is only worth wiring if it is (a) targeted/cheap on complex trees, (b) stable across OS versions. If found, its integration point is the cap-expiry branch of the baseline-distrust logic (replace "accept possibly-stale" with "force one fresh read"), not a new unconditional step.
Deliverable: measurement-backed GO/NO-GO with per-tree-size timings on the test-app + a Bluesky-class deep screen; implement only after sign-off.
Investigated via XCUIAutomation.framework disassembly (Xcode 26.2) + live pixel-vs-tree measurement (iPhone 17 Pro / iOS 26.2, test-app + Bluesky Following feed via Metro).
There is no stale cached tree on the runner's snapshot path to invalidate.element.snapshot() resolves the query (the only cache-eligible step — XCUISnapshotGenerationTracker gates which element handle, not tree data) then performs a live AX fetch of tree contents on every call. The generation cache is invalidated by a CFRunLoopObserver on every main-runloop entry, so its window is far shorter than one stabilization poll.
Deep screens harden the NO-GO from two directions: on a 147-node Bluesky feed the XCTest tier is already penalized/deferred and the private-ax backend serves instead — which calls the AX server directly and never touches the XCUIAutomation cache, so an invalidation hook would be a no-op precisely where it was proposed. And one forced fresh read there costs ~2.9s warm (23s cold) — worse than the bounded distrust cap it would replace. The private-ax bridge is also simulator-only (#if os(iOS) && targetEnvironment(simulator)), so it could never serve device-side.
Live staleness controls found no staleness anywhere: working scrolls move pixels and tree together with no lag (test-app and Bluesky); an inert gesture pan left the tree "frozen" at pre-gesture values — and the screenshot confirmed the screen genuinely had not moved. The tree was accurate; the gesture was a no-op.
Consequence beyond this spike: the checkout-form step-11 failure attributed to "stale-but-fast AX" (defect 2 in #1542/#1559) reproduced with evidence pointing to a genuinely inert scroll, not stale observation — the pixel-vs-tree adjudication has been handed to the in-flight fix workstream before it ships an observation-side fix for what may be a gesture-efficacy defect.
Invalidation hooks do exist for the record (writable XCUIApplication.generation, XCUIElement.lastSnapshot, or forcing a runloop entry) — they are simply not needed, and were this ever revisited, the integration point remains the cap-expiry branch only.
Activity
thymikee commentedon Aug 3, 2026
Spike verdict: NO-GO
Investigated via XCUIAutomation.framework disassembly (Xcode 26.2) + live pixel-vs-tree measurement (iPhone 17 Pro / iOS 26.2, test-app + Bluesky Following feed via Metro).
There is no stale cached tree on the runner's snapshot path to invalidate.
element.snapshot()resolves the query (the only cache-eligible step —XCUISnapshotGenerationTrackergates which element handle, not tree data) then performs a live AX fetch of tree contents on every call. The generation cache is invalidated by aCFRunLoopObserveron every main-runloop entry, so its window is far shorter than one stabilization poll.Deep screens harden the NO-GO from two directions: on a 147-node Bluesky feed the XCTest tier is already penalized/deferred and the
private-axbackend serves instead — which calls the AX server directly and never touches the XCUIAutomation cache, so an invalidation hook would be a no-op precisely where it was proposed. And one forced fresh read there costs ~2.9s warm (23s cold) — worse than the bounded distrust cap it would replace. The private-ax bridge is also simulator-only (#if os(iOS) && targetEnvironment(simulator)), so it could never serve device-side.Live staleness controls found no staleness anywhere: working scrolls move pixels and tree together with no lag (test-app and Bluesky); an inert
gesture panleft the tree "frozen" at pre-gesture values — and the screenshot confirmed the screen genuinely had not moved. The tree was accurate; the gesture was a no-op.Consequence beyond this spike: the checkout-form step-11 failure attributed to "stale-but-fast AX" (defect 2 in #1542/#1559) reproduced with evidence pointing to a genuinely inert scroll, not stale observation — the pixel-vs-tree adjudication has been handed to the in-flight fix workstream before it ships an observation-side fix for what may be a gesture-efficacy defect.
Invalidation hooks do exist for the record (writable
XCUIApplication.generation,XCUIElement.lastSnapshot, or forcing a runloop entry) — they are simply not needed, and were this ever revisited, the integration point remains the cap-expiry branch only.Generated by Claude Code