fix(mobile): reject stale refs after transition refresh

SH
2h ago
+47-7

What and why

  • When a transition refresh no longer lists the same control, fail with retryable NODE_STALE before sending input. The existing locator loop resolves the selector again within its timeout.
  • Clarify that contract in settled() and relocated(), remove the repeated inline comment, and describe the user-visible result in one sentence.
  • Related: #1297 determines when keyboard changes require a refresh. This PR handles a target disappearing or changing during that refresh. They address different contracts and overlap in relocated(): merge this fix first, then retain its stale check when rebasing #1297. A disposable checkout combining the runtime fixes passed all 367 mobile unit tests after resolving the binding-argument overlap; neither adds an input retry after possible dispatch.

Issue

Closes #1299.

Verified

Ran it locally: no new device run for this documentation-only follow-up.

Head: 1454929f42e405ff99823c89163abe7e6cf8146d.
pnpm check passes; all 344 mobile unit tests pass. Fresh-context review has no important or critical findings. Runtime behavior is unchanged by the review follow-up.

The existing scripted-client regressions cover both a disappearing target and a reused native reference. The independent review at c076670 confirmed they fail with surface.ts reverted to main and pass with the fix:

ScenarioMainThis PR
Target absent after refreshDispatches stale bindingNODE_STALE, no input
Old reference reused by another controlDispatches wrong bindingLocator resolves intended control again

The earlier downstream device evidence is private and is not attached. It established compatibility, not deterministic elimination of every navigation race. No upstream benchmark or Android device pass is claimed.