The difficult part of cancellation was not changing a label. Target verification, file checking or checkpoint storage might still be waiting when the person stops a task. If the continuation trusts its old permission, the cancelled request comes back to life. I check whether the same run still owns the continuation after the wait.
An entry check cannot protect an asynchronous gap
ActionBroker.execute checks runEpoch and running status at entry, then awaits a prepared checkpoint. The person can take control during that storage operation, so check runs again immediately afterward. Passing the beginning of a function does not freeze its authority until the end.
RunEpoch identifies an execution generation, not a refresh counter or success count. A mismatch between the captured and current generation produces STALE_RUN. Even when a task ID survives a stop and resume, its old continuation must not borrow the new execution's authority. The check belongs after the asynchronous boundary that can outlive the original permission.
Even a pre-dispatch checkpoint can outlive permission
The dispatch callback awaits a dispatched checkpoint, rechecks the generation, and only then changes its internal dispatched flag. A stored status label and the actual external effect are different events. Cancellation in that gap must not be ignored merely because a checkpoint has a promising name.
I mark what each await is waiting for, including slow storage. Treating only network requests as concurrency boundaries misses a continuation after a disk or database write. This pattern rejects stale authority before the next delivery; it does not make all external effects atomically cancellable. A reviewer should trace the actual call after the checkpoint rather than infer an effect from a recorded word.
Stopping changes the generation and cleans separate resources
TaskController.stop increments the generation and records paused or cancelled. It also aborts, resolves pending approval as false, clears its timer, stops the worker and asks the scoped host to stop task pages. A separate DNS path checks task ID and generation again after resolution. Changing a display label alone would leave those waits alive.
The summary explicitly says that previously delivered actions were not undone and their outcome needs checking. An external save may remain while further delivery is forbidden. Both facts are necessary. A UI that describes cancellation as a rollback can lead the next operator to repeat an action whose server-side effect already exists.
The counterexample changes control during verification
The broker test substitutes verifyTarget with a function that changes runEpoch. It expects STALE_RUN and asserts that selectTab was never called. A normal successful-selection test would not exercise that boundary. A ready response does not authorize a transition after current control has disappeared.
I reviewed the original code and test without stopping the person's running application. The substituted target-verification test does not prove instantaneous cancellation of every operational action. The linked lane module separately demonstrates that an old owner cannot release a newer run; it is not a complete implementation of browser cancellation. Preserve those narrower claims when adapting either pattern.
Report cancellation together with effects that may remain
The design rule is to recheck authority after a wait and reject stale results from current state. Previously dispatched effects remain subjects for separate read-only outcome checks. A stop request, executor termination and external-result verification each need their own evidence.
For publishing, payment or file replacement, first identify the delivery boundary. Returning cancelled from a catch block alone does not tell the operator what still exists. Useful cancellation reporting explains which continuation was rejected and which effect may already have crossed the boundary. That precision turns a stop button into an operational control rather than an optimistic promise.