A slow response after clicking invites another click. In automation, however, the first input may already have reached the server. While building Northstar I stopped treating a timeout as simple failure and retained the original input together with the expectation that still needed to be verified.

The failure position changes the next justified action

Failing before a button is found differs from dispatching the click and then failing to read its outcome. The first can justify observing and locating again. In the second, another click may create a second external effect. Dispatch state therefore matters more to recovery than a generic error label alone.

ActionBroker checkpoints prepared at step start and dispatched before the actual handoff. An error is classified according to dispatch and uncertain-outcome conditions. This is not a universal exactly-once protocol for external processing. It does give the next decision an anchor in the original input rather than an unsupported guess.

State the expected change before dispatch

clickAndWait and Enter receive an expected URL, text or state. If that condition is already true before input, it cannot establish a new action's success, so EXPECTATION_ALREADY_TRUE rejects it. Switching to a plain click cannot bypass the requirement. Verification starts by identifying what needs to change.

The URL checks distinguish exact URLs from route matching rather than accept a vague substring. State expectations also require a unique semantic target. These checks do not understand every site's business meaning, but they reduce the possibility of replacing the success criterion with a convenient one after the fact.

Retain the original condition when the result is late

When input was dispatched but its expectation was not established within the deadline, pendingOutcome stores the tab, original expectation and step record. OUTCOME_UNKNOWN means the post-dispatch result remains unverified, not that the action failed and should be repeated. Reads and outcome verification take precedence over another mutation.

Starting another task or changing IDs to hide that state would not remove a change already made on the server. A convenient agent tool should preserve grounds for the next action rather than merely clear an error quickly. Renaming a record cannot reconcile the original external effect.

verifyOutcome does not press the button again

verifyOutcome follows the pending outcome for the same tab and waits for the original expectation. If established, it records verification for the original step and the verification step and releases the pending state. Its result identifies the method as original_expectation_without_reclick. It is a path for proving a late result without dispatching the mutation again.

If that check also fails, uncertainty must remain. Replacing the expectation with an easier condition is not reconciliation. A flow stopped partway through also has completed and remaining steps; one late success does not automatically establish completion of the whole sequence. Recovery should match the scope of the original action.

What the shared waiting module can demonstrate

The shared wait module follows an existing run ID and scope and requires verified completion. Synthetic tests cover timeout, changed scope, success after a stop and unverified success. With no click or submit function, it lets a reader inspect the responsibility of not solving a waiting error by resubmission.

It is not the BrowserDriver that checks an expectation on a live page and does not replace all original protections comparing native input and server state. The synthetic rules, product action boundary and historical field tests are supplied as different kinds of evidence. Sharing a small implementation should not expand its claimed capability.

A design includes knowing where to stop

Business approvals, transfers and uploads can all encounter late responses. This article is not a rewrite of the existing ERP duplicate-request discussion; it concerns the boundary between actual browser input dispatch and document observation. On a web interface without a server-provided idempotency key, avoiding a guessed second click becomes especially important.

I inspected the current Broker and page API without deliberately breaking an operational browser run. Accurately retaining a state that cannot yet be recovered automatically is part of the goal. Persistence in completing a requested task differs from recreating an external effect without evidence. I wanted the code and its short status messages to preserve that distinction.