Split out from #1497 — Swift executor URLSession error audit. Section E — Cancellation gaps.
File references are to native/swift/Sources/wordpress-api/SafeRequestExecutor.swift unless noted; :NNN line numbers were verified against fix/converge-executor-error-classification.
Severity: medium. cancelRequest(withId:) (:151-170) looks up session.allTasks, then waits at most 1s for a didCreateTask notification; if no task appears, nothing records that the id was cancelled. During RetryAfterMiddleware's backoff no task is alive for up to max_retry_wait_seconds, and the retry request's uuid is only added to the context after cancel(context:) snapshotted context.requestIds() — the retry is never even targeted. Because uniffi 0.32's generated Swift never cancels Rust futures on Swift Task cancellation, cancel(context:) is the only effective cancellation for calls through the Rust core (fulfill(progress:) wires Progress.cancel() → cancel(context:)). Net: cancelling a media upload during a 429 backoff cancels nothing — the retry runs, the upload completes, and the caller sees success with no CancellationError. Fix: latch cancelled ids in the executor and cancel-on-creation in the didCreateTask callback, replacing the fire-and-forget 1s Combine timeout.
Severity: medium.
cancelRequest(withId:)(:151-170) looks upsession.allTasks, then waits at most 1s for adidCreateTasknotification; if no task appears, nothing records that the id was cancelled. DuringRetryAfterMiddleware's backoff no task is alive for up tomax_retry_wait_seconds, and the retry request's uuid is only added to the context aftercancel(context:)snapshottedcontext.requestIds()— the retry is never even targeted. Because uniffi 0.32's generated Swift never cancels Rust futures on Swift Task cancellation,cancel(context:)is the only effective cancellation for calls through the Rust core (fulfill(progress:)wiresProgress.cancel()→cancel(context:)). Net: cancelling a media upload during a 429 backoff cancels nothing — the retry runs, the upload completes, and the caller sees success with noCancellationError. Fix: latch cancelled ids in the executor and cancel-on-creation in thedidCreateTaskcallback, replacing the fire-and-forget 1s Combine timeout.