Skip to content

MOB-99: honor the documented settle delay after iOS accessibility activation - #46

Merged
GenericJam merged 2 commits into
masterfrom
fix/mob-99-ios-native-view-hit-testing
Aug 26, 2026
Merged

MOB-99: honor the documented settle delay after iOS accessibility activation#46
GenericJam merged 2 commits into
masterfrom
fix/mob-99-ios-native-view-hit-testing

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Summary

MobDev.Connector.connect_all/1 already called IOS.enable_accessibility/1 for every iOS simulator target, but never waited the ~500ms CLAUDE.md's own iOS accessibility activation section says to wait for the notifyutil broadcast to propagate before SwiftUI's accessibility tree is reliably ready to query. In practice wait_for_nodes's polling usually eats more than that anyway, but a caller driving taps the instant nodes connect had no actual guarantee — the gap between "documented requirement" and "code that enforces it" was real.

Companion PR (mob#84) retry-hardens the point-based accessibility lookup itself (find_a11y_at_point) as defense in depth for whatever residual race this doesn't fully close — the two fixes address the same underlying mechanism from both ends.

Test plan

  • mix test — 2117 passed
  • mix format / mix credo --strict — clean
  • Device-verified: full mix mob.connect pipeline against a fresh iOS simulator, then Mob.Test.frame/2 + Mob.Test.tap_id/2 called with zero artificial delay — succeeded, text field became first responder

See mob#84 for the full investigation writeup and an honest caveat about reproduction limits on the available hardware.

Linear: MOB-99 (companion PR: mob fix/mob-99-ios-native-view-hit-testing)

🤖 Generated with Claude Code

…ivation

MobDev.Connector.connect_all/1 has called IOS.enable_accessibility/1
for every iOS simulator target for a while, but never actually waited
the ~500ms CLAUDE.md's own iOS accessibility activation section says
to wait for the notifyutil broadcast to propagate before SwiftUI's
accessibility tree is reliably ready. In practice wait_for_nodes's
polling usually eats more than that anyway, but a caller driving taps
the instant nodes connect had no guarantee.

Companion fix in mob (ios/mob_nif.m) retry-hardens the point-based
accessibility lookup itself as defense in depth for whatever residual
race this doesn't fully close.
…not just iOS

From code review on PR #46:

Process.sleep(@ios_accessibility_settle_ms) was gated on
platform == :ios alone, which also matches physical devices —
IOS.enable_accessibility/1 shells out to `xcrun simctl spawn <udid>
...`, simulator-only tooling that's a no-op/error against a physical
UDID. Every mix mob.connect against a physical iPhone paid the full
500ms tax for zero benefit. Now gated on the same
platform == :ios && type == :simulator predicate
kill_stale_simulator_apps/1 already uses for the identical reason.

Not addressed (documented, not silently dropped): the fix is still a
bare fixed-duration sleep, not a poll-until-ready check. A real
readiness poll would need to run AFTER dist connects (there's no RPC
path into the device yet at this point in connect_all/1), which is a
bigger restructuring than this fix — flagging as a known limitation
rather than attempting it here. Original PR description already
disclosed this as "defense in depth for whatever residual race this
doesn't fully close."
@GenericJam
GenericJam merged commit 3797845 into master Aug 26, 2026
3 checks passed
GenericJam added a commit that referenced this pull request Aug 26, 2026
…ettle delay

Ships MOB-98 (mix mob.doctor detects the pre-fix component-event JNI
mismatch) and MOB-99 (the iOS accessibility settle delay only applies
to simulators, not physical devices), both merged from PR #45 and #46
with their review-fix follow-ups.

See CHANGELOG.md for the full breakdown.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant