Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

refactor(ios-runner): acquire first, present after — one geometry normalization pass instead of per-walker threading

已关闭
#2,661 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
28/100
Issue 类型
重构
描述清晰度
描述清楚
活跃度
活跃
技术栈
ios, swift

调研方向

Start with captureWithBackend, the recursive acquisition code in apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift, and SnapshotCoordinateSpace.swift. Run the deep-tree benchmark and existing rotated-output tests before changing the acquisition flow. Done means one post-acquisition normalized pass, no geometry threading in walkers, updated ADR 0004, passing package and runner suites, and benchmark results within the stated limit.

由索引模型根据 Issue 内容生成。

描述

ready-for-agent refactor

Why

In the XCTest runner, acquisition and presentation are interleaved in the recursive tier, so every geometric fact has to be threaded through every walker by hand.

Evidence from PR #2653 (fixes #2612), which added one fact, "which coordinate space is this node in":

  • It had to touch three walkers (recursiveTreeSnapshotAcquisition, rawTreeSnapshotAcquisition, the private-AX appendPrivateAXNode) plus the collapsed-tab side path (collapsedTabFallbackNodes / collapsedTabCandidateNode) in apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift and RunnerTests+PrivateAXPresentation.swift, adding geometrySpace / parentIsWindow parameters to each frame of each walk.
  • The query-sweep tier (querySweepSnapshotAcquisition) got nothing, because it has no window ancestry inside its walk, so that tier still publishes unnormalized geometry (ADR 0004, "What stays unnormalized").
  • The collapsed-tab expansion needed a special guard (guard geometrySpace == .appOrientation else { return [] }) because it reads live element frames that are already in the app's space.

The reason a post-acquisition pass could not do this in one place is at RunnerTests+Snapshot.swift around line 244: the recursive walk calls SnapshotPresentation.regularTraversalTransition(for: node, …) mid-walk, consulting the visibility fold to decide the presented depth and whether to descend. The fold reads node geometry, so geometry must be final before the fold sees it, so it must be computed inside the walk. The private-AX tier does not have this coupling: it acquires the whole raw tree and presents afterwards through SnapshotPresentation.present(acquisition, options:) (RunnerTests+SnapshotCapturePlan.swift, captureWithBackend).

Wider counts on main (same files): 9 production RawAXNode( construction sites across 5 files; 5 call sites reading RunnerSynthesizedGesture.interfaceOrientation(forApplication:); 13 sites reading the app viewport (app.frame, safeSnapshotViewport, app.windows.firstMatch.frame). The 2026-08-31 presenter-convergence review already flagged "presented-depth frontier coupling (acquisition consults fold decisions mid-traversal) must be redesigned before any runner demotion".

Task

Make the recursive tier acquire first and present after, like the private-AX tier already does, so that geometry normalization becomes one pass over the flat [RawAXNode] array.

  1. Establish what the mid-walk fold buys. The recursive tier walks XCUIElementSnapshot.children, which XCTest materialized in one bulk snapshot; the frontier does not save AX round trips, it saves walk time and node construction on subtrees the fold would clip. Measure on the deep-tree benchmark (scripts/ bench harness used for #2424 / the deep-tree work; see docs/ for the recipe) and on the test app: raw node count walked with and without the frontier, and wall time. Report the numbers before changing anything. If the frontier is load-bearing for a known hostile screen (Bluesky feed, #1105/#1156), keep a bound that does not consult presentation: a raw depth / node cap is acceptable, a fold decision is not.
  2. Acquire raw, then normalize, then present. Walkers produce RawAXNode with reported frames only. Add SnapshotGeometrySpace.normalized(nodes:viewport:interfaceOrientation:) -> [RawAXNode] next to the existing rule in apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotCoordinateSpace.swift: walk the array once, derive each node's space from type, parentIndex and rect with the existing space(reportedBySurfaceHost:…) rule, rewrite rect through orientedFrame(of:), and recompute hittable with SnapshotGeometry.isGeometricallyActionable. Run it once in captureWithBackend between acquisition and SnapshotPresentation.present. Delete the geometrySpace / parentIsWindow threading from every walker and the collapsed-tab guard (collapsed tab containers sit under the app's own window, so a post-pass keyed on ancestry never touches them).
  3. Bring the query-sweep tier under the same pass. Its flat nodes hang off the application root; with no window ancestry they declare no space and the pass leaves them alone, which is the current behaviour, but now for a structural reason rather than an omission. Say so in ADR 0004.
  4. Keep the disclosure. unplacedSurfaceHostCount (added after #2653) already runs post-acquisition; it should now run after normalization and be zero whenever the orientation was readable.

Acceptance criteria

  • SnapshotGeometrySpace is referenced from exactly one production site in apple/runner/** (the normalization call in captureWithBackend); no walker takes a geometrySpace or parentIsWindow parameter.
  • Every existing runner unit test that asserts rotated output still passes unchanged: testPrivateAXAcquisitionPublishesATurnedSurfaceHostInAppOrientationSpace, the RunnerTests+Snapshot.swift tests added in #2653, testStampedPayloadDisclosesUnplacedSurfaceHosts. The package suite (swift test --package-path apple/snapshot-presentation) gains a test for normalized(…) that replays the rotationCases of contracts/fixtures/window-coordinate-space.json through a two-window tree.
  • contracts/fixtures/snapshot-presentation-conformance.json, ios-snapshot-backend-conformance.json and ios-ax-recovery-conformance.json are unchanged and green in both languages.
  • Live: snapshot -i --json on the test app in portrait is byte-identical to main on the runner path (confirm the producer is apple-runner, not the bridge: the bridge fingerprint is the "does not provide hittability evidence" warning). In landscape with the keyboard up, the band and key rects match the #2653 numbers ((75,198,724,202) band, key q at (77,203,72,45)).
  • Benchmark: capture p50 and p95 on the deep-tree harness and on the Bluesky feed not regressed by more than 5 % against main, with the numbers in the PR. If the frontier had to be replaced by a raw cap, the cap and the screens it was calibrated on are named in ADR 0004.
  • pnpm check:affected --run green; runner units green under AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS=1; pnpm test:ios-snapshot-differential green.

Non-goals

Runner demotion or moving presentation to the host: that is a separate, measurement-gated decision (ADR 0004 host-side ownership boundary; two presenters was the measured optimum on 2026-08-31). Touching the Android or bridge producers.

Related: #2612, #2653, #1797 (acquire/present split), #2188 / #2199 (iOS snapshot convergence), ADR 0004.

主要语言
TypeScript
星标
5k
派生
334
平均合并
12 小时 13 分钟
30 天内合并 PR
723

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

callstack/agent-device 的其他 Issue

查看 callstack/agent-device 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。