Skip to content

fix(settle): iOS broad-transition confirmation fires on tab switches and pushes and is coupled to the default quiet window #3470

Open

Description

@thymikee

Problem

The iOS broad-transition confirmation in src/commands/interaction/runtime/stable-capture.ts (stableCaptureTransitionQuietMs, stableCaptureTransitionBaseline) was added in #1831 for one case: Element's modal dismissal, where a coherent but transitional tree beat the quiet window. In practice it also fires on ordinary navigation, and it is switched on and off by the requested window rather than by the transition.

  1. It fires on ordinary navigation. It fires whenever fewer than 50% of node identities are shared with the pre-action tree. With a complete viewport projection, that is true of most tab switches and screen pushes. Each one then costs 1.5 s.
    • Measured on an iPhone 17 simulator with the RN test app, 4 runs per step, median waitedMs:

      Settings Push Pop Tab Fill
      Default (rule on) 2302 1808 1795 1796
      150 ms, rule off 812 474 442 458
    • With the rule off, no step settled early. Each settled tree matched a capture taken 2 s later.

    • A push followed by a tap on the new screen's control, using the ref from the settle diff, landed 8 of 8 times.

  2. It is tied to the requested window. It is skipped when requestedQuietMs < DEFAULT_STABLE_QUIET_MS, so --settle-quiet 499 behaves completely differently from 500. tester-army/e2e passes settleQuietMs: 150 and therefore never gets the guard.

Required behavior

  • Narrow trigger. Arm the confirmation only for the transition it was built for: dismissal of a presented surface. Tab switches and pushes must not trigger it. The existing hasTinyPresentedBaseline arm is the starting point; arming on a complete viewport projection alone is not enough. If a better presentation signal exists, use it.
  • Independent of the window. Whether the confirmation applies must not depend on requestedQuietMs versus the default. Decide and document what an explicit short window means. Today's test stable-capture.test.ts:206 encodes the old coupling.
  • Keep fix: derive iOS transition snapshots from visible presentation #1831 covered. Its regression tests (stable-capture.test.ts:60-166) still pass: coherent transitional room, private-AX recovery, delayed replacement, advanced stored snapshot, missing provenance, rootless replacement.

Done when

  • Unit tests show a tab switch and a push no longer extend the window. The fix: derive iOS transition snapshots from visible presentation #1831 cases still do, at any requested window.
  • Live A/B on an iOS simulator at the default window, 4 or more runs, recording waitedMs and late diffs. Tab switch, push, pop and fill no longer pay about 1.5 s, with no new late diffs.

Related: #3469 (keyboard chrome) also affects this rule's input. A follow-up may change the default window per capture backend (see below), stacked on this change.

Follow-up layer (stacked PR, same worker): default window per capture backend

Delayed-effect probe on the same devices (6 runs per cell; caught = the settled diff already shows the result):

  • iOS XCTest (~250 ms per capture): 150 ms catches effects up to 500 ms but only 1 of 6 at 800 ms. 300 and 500 catch 800 ms.
  • Android helper (~100 ms per capture): 150 ms catches 2 of 6 at 250 ms; 300 ms catches 0 of 6 at 500 ms; 500 ms catches 0 of 6 at 800 ms.

Proposal: iOS XCTest tree capture defaults to 300 ms; everything else keeps 500, including standalone wait stable. Key the default on the capture backend, not the platform name.

Measure before and after. If the median saving on local changes is under 10%, close the follow-up and report back rather than shipping. It is a user-visible change, so update the --settle-quiet description (packages/command-registry/src/flag-definitions-action.ts:203) and src/commands/post-action-observation-grammar.ts:36.

Activity

  1. added 10 commits that reference this issue on Oct 12, 2026
    b8d7540
    a565d42
    4ada6aa
    1f97dfc
    a3dc159
    183801d
    4952ad4
    3a25bb2
    76bbe24
    aa3ab64
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions