The client is answered at step 8, before any task has run. Everything after that point is recoverable from Cosmos alone, so a 202 is a durable promise rather than an optimistic one.
The Idempotency-Key header makes submission itself idempotent. A client retrying a timed-out POST gets the same executionId rather than a second execution — the requirement's idempotency rule applied at the front door as well as at the worker.
The dispatch message carries the taskExecutionId as its MessageId, which lets Service Bus duplicate detection suppress relay-level double sends within a 10-minute window without anyone claiming exactly-once.
Latency budget
p95 under 300 ms for steps 1 to 8: roughly 30 ms at API Management, 40 ms for the version read, 60 ms for the batch write, the rest network and serialisation.
p95 under 1 second from commit to a message on the queue, which is change-feed latency plus relay processing. This is the number that KEDA's oldest-message-age trigger in view 24 is scaled against.
The version read is a point read inside the tenant partition and is cached per pod for 60 seconds, because an immutable version is safe to cache indefinitely.
Failure behaviour
If the batch write fails, the client gets 503 and nothing exists. This is the only clean failure point in the flow, which is why it is placed before the response.
If the relay dies between send and marking published_at, the message is sent twice. Duplicate detection catches it inside 10 minutes; the worker's idempotency catches it after that (view 17).
If Service Bus is unavailable, submissions still succeed and outbox rows accumulate. Dispatch resumes on recovery with no data loss and a visible lag metric.