refactor(ios): move the coordinate-space rule into the presentation package - #2664
Conversation
…se 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.
Size Report
Startup median (7 runs, lower is better):
|
|
Reviewed 6cfe6a5. The code looks right, but one gap stops me from calling it ready: nothing live shows that the moved geometry code still works on a device.
Non-blocking, take or leave: The package grows 8.6 kB unpacked, over the 3 kB mark. Most of that looks like the comments of the moved Swift file: runner sources go through comment stripping in One question I could not settle from the code: does the counter's One Smoke Tests job was still running at review time. It is not independent of this change, because iOS smoke builds the runner that now compiles |
… 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.
|
Live validation done on iPhone 17 Pro (iOS 26.2 Simulator), runner route ( (a) Landscape, keyboard up. Safari address field focused after
(b) Portrait, keyboard up. App frame 402×874: keyboard band at y 583 w 402 h 233, 33 key nodes, no So the moved geometry code and both walker call sites are correct on a real tree. Took the two non-blocking points, and the answers to the two questions: Scope default. Agreed — removed it. Overcount. Fixed.
Package size / comment stripping. The presentation package is already comment-stripped in Smoke Tests / iOS runner build. Green on the pushed head, and I rebuilt the runner locally with One heads-up unrelated to the review: #2669 and #2670 (the #2661 and #2660 workers) overlap this PR. I left merge-order notes on both — this lands first, they rebase to the behaviour layer. Details on those PRs. |
|
Reviewed 5f93e58. The code looks right, and nothing blocks it. The runner-route landscape and portrait snapshots you posted for 5f93e58 close the gap from my last review: the keyboard band is in app space, and neither orientation shows All 18 checks pass on 5f93e58, including the iOS smoke job that builds the runner with the moved Non-blocking, fine for a follow-up: the TypeScript twin |
…e 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.
|
Correction, and a cut. Head I was wrong about the package size, and your hypothesis was right. I claimed the presentation package was comment-stripped in Measured with What this head keeps: only the move. The file is rewritten in the package's style (no prose; rationale stays in ADR 0004 and the fixture description), same code, Cut, and why:
Validation on |
|
Reviewed 321aef2. The code looks clean. Since 5f93e58 the change only drops the failure-scope field and the unplaced-geometry disclosure, and the TS side of those files is back to main. The moved Your live landscape and portrait captures still cover this head, because the delta does not change the walker call sites or the rotation logic. I did not rerun Smoke Tests is still running on 321aef2. It builds the runner, which now uses the moved file, so it needs to finish green before merge. There are no conflicts. Not blocking: SnapshotCoordinateSpace.swift#L4-L6 still has a 3-line header comment, and the package ships its sources as they are, so you can delete it (ADR 0004 and the fixture already hold that rationale) or leave it. |
|
Summary
Moves the rotation table and the coordinate-space rule (
RunnerInterfaceOrientation,CoordinateSpaceRotation,SnapshotGeometrySpace) out of the XCTest runner bundle intoAgentDeviceSnapshotPresentationasSnapshotCoordinateSpace.swift,public, written in that package's comment-free style.isSurfaceHosttakesisWindow/parentIsWindowbooleans instead of anXCUIElement.ElementTypeso the file has no XCTest dependency; the two runner walkers passisWindowElement(...). The six rotation/space tests and the golden-table replay move into the package suite (CoordinateSpaceTests), soswift testproves the table on any macOS host without a simulator.No behaviour change. ADR 0004 gains a pointer to the #2659 spike verdict (the bridge cannot read interface orientation; measured) and names the package as the rule's home.
Package size delta vs main measured with
npm pack --dry-run --ignore-scripts: +25 bytes.Two earlier pieces (a failure-scope field and an unplaced-geometry disclosure) were tried and cut; the reasoning is in the review thread.
Follow-ups filed from the same review: #2659 (spike, closed), #2660, #2661, #2662.
Validation
Head
321aef2.pnpm typecheck,pnpm format:checkclean; touched TS test files are main's (74 pass).swift test --package-path apple/snapshot-presentation22/22. Runner built withAGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS=1(arm64);testPrivateAXAcquisitionPublishesATurnedSurfaceHostInAppOrientationSpace,testScrollViewportDispatchKeepsTheUnclippedFrameAsItsCoordinateRotationBasis,testStampedPayloadTruncationTracksCompletenessNotRecoveryProvenancepass on a throwaway iPhone 17 Pro (iOS 26.2). Live runner-route captures (Safari, keyboard up): landscape bandx 75 y 238 w 724 h 162, keyqatx 77 y 243 w 72 h 35, 31 keys; portrait bandy 583 w 402 h 233, 33 keys — both in app space, no coordinate-space warning.