wait still refuses an unverified-hittability wrapper chain
PR #2482 (merged as c94e66e) collapses an unverified-hittability wrapper chain for the action-target resolution only: press/click/fill/longpress, the is target verification, and the post-action settle observation. Issue #2480 was closed by that merge, but its second half is not fixed, so I am opening this to keep it tracked rather than lost.
Symptom (0.21.0 and current main)
A SwiftUI toolbar item that carries an accessibility identifier yields two nodes: the wrapper Other and the Button under it, with no hittability evidence and rects ~0.7-1 pt apart.
$ agent-device press 'id="scoring_home_button"' --settle
Error (AMBIGUOUS_MATCH): Selector matched 2 distinct actionable elements: id="scoring_home_button"
Candidates: @e3 [other] "Home" @e4 [button] "Home" <- fixed by #2482
$ agent-device wait 'id="scoring_home_button"' 3000
Error (AMBIGUOUS_MATCH): selector matched multiple elements
Diagnostics Log: .../runner.log <- still fails
Observed screen state in both cases: scoring_home_button -> Other [20,63,36,36] + Button [21,63,35,36].
Why it is a separate path
wait does not run the action-target resolution. src/daemon/wait-runtime.ts builds its own selector runtime:
src/daemon/wait-runtime.ts:46 await bindWaitOperations(params, parsed, session, device)
src/daemon/wait-runtime.ts:156 const runtime = createSelectorRuntimeForDevice({ ... })
classifyActionableTouchCandidates is reached only from src/commands/interaction/runtime/selector-action-resolution.ts (called by resolution.ts), which wait never imports. On iOS the refusal surfaces from the native runner, which does not use the shared structural-equivalence rules:
apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift:1683
apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift:238
Options
- Delegate: have the runner hand its multi-match decision to the shared equivalence rules, so the selector layer and the runner cannot drift.
- Mirror: re-implement the wrapper-chain rule inside the runner.
Option 1 is preferable: the two layers disagree today, and mirroring guarantees a future divergence.
Verification
A device lane is required: an iOS simulator run of press + wait against one toolbar control, with the same screen state recorded on both sides. I can prepare the patch and run that lane if you pick a shape.
waitstill refuses an unverified-hittability wrapper chainPR #2482 (merged as
c94e66e) collapses an unverified-hittability wrapper chain for the action-target resolution only:press/click/fill/longpress, theistarget verification, and the post-action settle observation. Issue #2480 was closed by that merge, but its second half is not fixed, so I am opening this to keep it tracked rather than lost.Symptom (0.21.0 and current
main)A SwiftUI toolbar item that carries an accessibility identifier yields two nodes: the wrapper
Otherand theButtonunder it, with no hittability evidence and rects ~0.7-1 pt apart.Observed screen state in both cases:
scoring_home_button->Other [20,63,36,36]+Button [21,63,35,36].Why it is a separate path
waitdoes not run the action-target resolution.src/daemon/wait-runtime.tsbuilds its own selector runtime:classifyActionableTouchCandidatesis reached only fromsrc/commands/interaction/runtime/selector-action-resolution.ts(called byresolution.ts), whichwaitnever imports. On iOS the refusal surfaces from the native runner, which does not use the shared structural-equivalence rules:apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift:1683apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift:238Options
Option 1 is preferable: the two layers disagree today, and mirroring guarantees a future divergence.
Verification
A device lane is required: an iOS simulator run of
press+waitagainst one toolbar control, with the same screen state recorded on both sides. I can prepare the patch and run that lane if you pick a shape.