fix(flow): wait for iOS instrumentation before capturing a recorded tap - #723
Draft
hubgan wants to merge 5 commits into
Draft
fix(flow): wait for iOS instrumentation before capturing a recorded tap#723hubgan wants to merge 5 commits into
hubgan wants to merge 5 commits into
Conversation
hubgan
force-pushed
the
fix/recorder-ios-instrumentation-wait
branch
from
August 4, 2026 07:23
4b59f84 to
e88a71a
Compare
hubgan
force-pushed
the
fix/recorder-ios-instrumentation-wait
branch
from
August 5, 2026 10:15
5926b40 to
32aacef
Compare
hubgan
force-pushed
the
fix/recorder-ios-instrumentation-wait
branch
from
August 5, 2026 10:38
32aacef to
638aa11
Compare
hubgan
force-pushed
the
fix/recorder-ios-instrumentation-wait
branch
from
August 6, 2026 09:58
638aa11 to
7f882cd
Compare
hubgan
force-pushed
the
fix/recorder-ios-instrumentation-wait
branch
2 times, most recently
from
August 10, 2026 08:47
64bdebe to
f592c53
Compare
Recording had no counterpart to replay's launch readiness gate. A live `restart-app` returns before the injected dylib dials back, so a tap recorded right after one read the tree before the app had connected, found nothing, and silently kept coordinates — the very first tap of a walkthrough, and the one most likely to be repeated. The recorder now rides out that window before the tree read, on the same budget replay uses: a cold start the replay gate would absorb, recording absorbs too. With a leading `launch` it polls the exact bundle's connection bit, the same check replay makes; a fragment polls until auto-targeting finds one connected, foreground-like app. Three cases had to stay cheap or correct: - An app started OUTSIDE Argent can never connect during this recording, so one exhausted probe is remembered per device and session — otherwise a 20-tap walkthrough pays the full budget 20 times. A successful tree read, or a successful launch/restart, clears it so instrumentation arriving later still works. - An Apple system app can never inject at all, so it is not polled. - The fragment path inspects app state over an RPC that can itself wedge, so it is raced against the remaining budget — the gate stays a hard cap rather than becoming 8 seconds BETWEEN multi-second calls. Cancellation now propagates: a disconnect during the poll aborts the call instead of merely stopping the poll and then executing the tap anyway.
…ding one The recorder's iOS readiness gate resolved which launch to wait on from the LEADING launch step, but fetchFlowTree reads the frontmost connected app. A recording that relaunches a second app mid-flow (restart A … restart B … tap) polled A's connection bit — still set, since restart-app B never touched A — and returned ready at once, reading B's tree before its dylib had dialed back and downgrading the tap to coordinates: the exact failure the gate exists to prevent. Replay gates each launch step on its own bundle. Resolve the launch app from the most recent launch instead; it reduces to the leading launch for the common single-launch flow. Add tests covering the exact-bundle isConnected ready path (previously uncovered) and the mid-flow app switch.
…de-out
The two exact-bundle tests ("polls the leading launch's exact bundle" and
"gates on the most recent launch") set the tree unconditionally, so their
message/step assertions passed even with the gate's wait removed — only the
isConnected keying was load-bearing. Throw until connected (as the auto-target
ride-out test already does) so a gate that reads the tree before the app
connects downgrades to coordinates and the assertions catch it.
Also cover two reachable branches that had no test: launch-app's launched:true
clearing the readiness miss-cache (symmetric with restart-app), and the
auto-target settleWithin error result (a rejecting getAppState) keeping the
poll alive to the budget rather than aborting early.
hubgan
force-pushed
the
fix/recorder-ios-instrumentation-wait
branch
from
August 10, 2026 08:55
f592c53 to
690c5fe
Compare
…-instrumentation-wait
…-instrumentation-wait
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
Replay has a launch readiness gate. Recording had no counterpart.
A live
restart-appreturns before the injected dylib dials back, so a tap recorded right after one read the tree before the app had connected, found nothing, and silently kept coordinates — with only the generic capture warning to show for it. That is the first tap of a walkthrough, and the one most likely to be repeated across takes.What changes
The recorder rides out that window before reading the tree, on the same budget replay uses: a cold start the replay gate would absorb, recording absorbs too.
launch, it polls the exact bundle's connection bit — the same synchronous check replay makes.When the budget lapses it stops and lets the single tree read report whatever is really there, so the capture warning stays accurate rather than being replaced by a timeout.
Three cases that had to stay cheap or correct
An app started outside Argent can never connect during this recording. One exhausted probe is remembered per device and per recording session — otherwise a 20-tap walkthrough pays the full budget twenty times. A successful tree read, or a successful
launch-app/restart-app, clears the entry, so instrumentation that becomes available later still gets picked up.An Apple system app can never inject at all (library validation), so it is not polled.
The fragment path inspects app state over an RPC that can itself wedge. It is raced against the remaining budget, so the gate stays a hard cap rather than becoming 8 seconds between potentially multi-second calls.
Cancellation
A disconnect during the readiness poll now aborts the call. Previously it stopped the poll and then executed the tap anyway — moving the device after the caller had given up.
Cost
When the app was never Argent-launched, this adds one budget's worth of latency before the (accurate) capture warning. That is the deliberate trade: it beats silently downgrading a post-launch tap to coordinates.