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
Fail closed for unresolved synthesized coordinate fill on iOS #1721
The iOS coordinate fill path can use synthesized-first-responder-replacement when the requested coordinate does not resolve to a concrete text-entry element, a refresh point exists, and the XCTest channel is penalized. In that state, replacement is dispatched through the application-level first responder without concrete element identity or post-write verification.
If focus still belongs to a previous field, an unresolved coordinate fill can therefore replace text in the wrong input while returning a completed result with verified: nil. This behavior predates #1700; it is separate from the bare-type witness fix merged there. It is also distinct from #1718, which tracks parent-owned touch-point parity for direct selectors and Maestro.
Relevant seams:
RunnerTests+SynthesizedTextEntry.swift: shouldUseSynthesizedFirstResponderReplacement and runSynthesizedReplacementRoute
RunnerTests+TextEntry.swift: coordinate target resolution and refresh-point fallback
src/platforms/apple/interactions.ts: coordinate fill dispatches replacement mode
Closure
Fail closed when coordinate fill cannot bind synthesized replacement to the intended text-entry target, or introduce a concrete target/commit signal that provides equivalent safety.
Add a red/green iOS regression proving an unresolved coordinate fill cannot mutate a previously focused field.
Preserve the penalized-channel replacement path for a concretely resolved coordinate target.
Report a structured actionable failure instead of an unverified success when safe replacement cannot be established.
Update the interaction guarantee classification and contract coverage if the fix changes a declared dispatch-path guarantee.
Re-checked against main after #3201. Only partly fixed, so keeping this open.
#3201 covers the case where an input sits under the point: coordinateTapTextInputIdentityAt binds the target to that input's identity before the tap (RunnerTests+TypeExecution.swift), and reads and clears then refuse any other field.
The case this issue names still behaves the same. When nothing is under the point, or the probe can't answer, inputAtPoint is nil, so the target is unbound. shouldUseSynthesizedFirstResponderReplacement(hasResolvedElement: false, hasRefreshPoint: true, penalized: true) still sends it down the replacement route (RunnerTests+SynthesizedTextEntry.swift). The route types through the app-level first responder. Its clear read and commit wait go through resolveUnboundTextEntryElement, which falls back to focusedTextInput. If an earlier field still has focus, the fill replaces that field's text and the commit wait reports success on the wrong field.
Smallest fix: on the penalized coordinate route, when inputAtPoint is nil, refuse with a typed reason (no text input at the point) before the replacement route runs. Add the red/green regression from the closure list.
Activity
thymikee commentedon Oct 8, 2026
Re-checked against main after #3201. Only partly fixed, so keeping this open.
#3201 covers the case where an input sits under the point:
coordinateTapTextInputIdentityAtbinds the target to that input's identity before the tap (RunnerTests+TypeExecution.swift), and reads and clears then refuse any other field.The case this issue names still behaves the same. When nothing is under the point, or the probe can't answer,
inputAtPointis nil, so the target is unbound.shouldUseSynthesizedFirstResponderReplacement(hasResolvedElement: false, hasRefreshPoint: true, penalized: true)still sends it down the replacement route (RunnerTests+SynthesizedTextEntry.swift). The route types through the app-level first responder. Its clear read and commit wait go throughresolveUnboundTextEntryElement, which falls back tofocusedTextInput. If an earlier field still has focus, the fill replaces that field's text and the commit wait reports success on the wrong field.Smallest fix: on the penalized coordinate route, when
inputAtPointis nil, refuse with a typed reason (no text input at the point) before the replacement route runs. Add the red/green regression from the closure list.