Conversation
…ion from the AX bridge Measures all three candidate routes on iPhone 17 Pro (iOS 26.2). Route 1's XC_kAXXCAttributeApplicationOrientation resolves to id 1503 but the guest's snapshot channel returns 0 and XCTest's own reader fails kAXErrorServerNotFound; route 3's only working read (BKHIDServicesGetCurrentDeviceOrientation) is device orientation, which diverges from the foreground app's interface orientation on a rotation-locked app; route 2 is a keyboard-band heuristic. No cheap, reliable interface-orientation fact is available to the guest, so #2653's detect-and-refuse layer and the ADR 0004 refusal stand.
Member
Author
|
Reviewed 2965c9c. This is a docs-only spike record, and its conclusion follows from the measurements it reports: none of the three routes gives a cheap, reliable interface-orientation fact, so the #2653 refusal stays. I did not re-run the Simulator measurements; the appendix commands make them reproducible. Checks are green, and this is ready for human review. |
4 tasks
Member
Author
|
Closing unmerged on purpose: the answer is a negative result and does not need a 200-line doc in the repo. The verdict and the bar for a future attempt are recorded on #2659; ADR 0004 and |
|
thymikee
added a commit
that referenced
this pull request
Sep 19, 2026
…ackage (#2664) * refactor(ios): declare bridge failure scope at the throw site, disclose unplaced surface hosts, move the coordinate-space rule into the presentation package Three follow-ups to #2653 (fixes #2612), each inside that PR's own new code. Failure scope. Whether a Simulator AX bridge failure retires the app generation from the bridge was decided at the route by matching the failure's kind and code. SnapshotSourceFailure now carries scope: 'capture' | 'generation', set where the failure is thrown (snapshotSourceCaptureError for bridge-preparation-pending and window-coordinate-space-unresolved), and the route reads the field. Disclosure. A runner capture that could not turn a rotated surface host back (orientation unreadable, or the private-AX tier anchored on the bridge's root box) published two coordinate spaces silently. SnapshotGeometrySpace.unplacedSurfaceHostCount runs after every tier's acquisition; a non-zero count rides the quality verdict as unresolvedCoordinateSpaceWindows and the daemon renders a warning. Package. The rotation table and the coordinate-space rule are pure CoreGraphics and now live in AgentDeviceSnapshotPresentation (SnapshotCoordinateSpace.swift) with their tests in the package suite, so swift test replays the golden table without a simulator. isSurfaceHost takes booleans instead of an XCUIElement.ElementType. * docs(ios): point the bridge refusal decision at the #2659 spike verdict The ADR 0004 refusal decision and the TS detector's header now cite the measurement (issue #2659, diff of #2667): the AX orientation attribute resolves but reads 0 through the guest channel, and the only cheap service read is device orientation, which diverges on a rotation-locked app. * refactor(ios): make failure scope a required constructor arg; count a turned surface once Addresses review on #2664. - SnapshotSourceError takes scope as a required argument (no 'generation' default), positioned after the required code. The two factories name their side: snapshotSourceError -> 'generation', snapshotSourceCaptureError -> 'capture'. New errors.test.ts pins both. - unplacedSurfaceHostCount folds a turned surface's window and the surface directly under it into one host, so the disclosed count is a surface count even when both report the turned box. Package test covers the both-turned pair. * refactor(ios): keep only the coordinate-space package move; drop scope field and unplaced-geometry disclosure Measured against main with npm pack: the earlier +9.3 kB was 6.8 kB of prose comments in the moved file (the presentation package is written comment-free and copied verbatim), ~1.5 kB of disclosure plumbing, and ~0.2 kB for the failure scope field. The move alone is now +25 bytes. - Moved file rewritten in the package's comment-free style; rationale stays in ADR 0004 and the golden fixture description. - Failure scope field reverted to main's opensGenerationCircuit predicate: a required constructor argument guarded what the route tests already guard, for two fixed codes. - unresolvedCoordinateSpaceWindows disclosure reverted: its only trigger path (private-AX tier with a penalized XCTest channel) anchors on a root frame whose space is unmeasured and is infinite in the common case, so the count is zero by construction there; never observed live. Noted on #2661 where one-pass normalization makes it a measured one-liner if ever wanted. - ADR 0004 keeps the #2659 spike pointer and the package-home sentence only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Answers the #2659 spike: can the Simulator AX bridge guest learn the foreground app's
UIInterfaceOrientationcheaply and reliably at capture time? Measured on iPhone 17 Pro (iOS 26.2) with throwaway guests compiled exactly like the bridge andxcrun simctl spawn.XC_kAXXCAttributeApplicationOrientationresolves (id 1503) via the bridge's own resolver, butuserTestingSnapshotForElement:returns 0 on the root and every window in all orientations, and XCTest'sappOrientationForElement:error:failskAXErrorServerNotFoundfrom a remote-access guest.BKHIDServicesGetCurrentDeviceOrientation(~0.015 ms), is device orientation; it diverges from the app's interface orientation on a rotation-locked app (Settings stayed portrait(0,0,402,874)while the device read3). SpringBoard interface getters return a fixed non-enum0x10000003.No route delivers a cheap, reliable interface-orientation fact, so #2653's detect-and-refuse layer and the ADR 0004 refusal stand; the delete-the-layer plan is not unlocked. Deliverable is the doc
docs/ios-bridge-orientation-read-spike.md(Appendix carries the reproduction commands). No production code merged. Docs-only, one file.Closes #2659.
Validation
Docs-only:
pnpm check:affected --run→ "Docs-only changes ignored … all runnable checks passed." No runtime path changed, so no device/runtime validation applies. The measurements behind the findings were taken live on the iPhone 17 Pro Simulator (iOS 26.2) viasimctl spawnguests andagent-device orientation; the runner's owninterfaceOrientationForApplication:value is not host-exposed, so interface-space truth was witnessed by captured window geometry plus a rotation-locked Settings divergence — recorded as a scope limit in the doc. Physical devices out of scope (bridge is Simulator-only).