No ToTask, ever — the test exemption is retracted
The guidance used to say tests were the one sanctioned place to bridge an observable to a Task.
That exemption never held: a Task completed from inside an Rx pipeline resumes its awaiter
inline, on the signalling thread, still inside Rx's trampoline, and everything the continuation
does inherits that — so a bridge written "only in a test" changes how the code under test runs.
⚠️ Corrected 2026-09-18 — the paragraph below was wrong, and this is where the mistake started. It recommended awaiting the observable directly. That is the same defect in fewer characters: Rx's own awaiter is an
AsyncSubject<T>that completes its continuation from insideOnCompleted, so it resumes inline on the signalling thread exactly as.ToTask()does. What a test should write instead is an assertion on the stream —await x.Should().Within(TestTimeouts.Convergence).Emit("because")— or, where anasync Tasksignature genuinely must take a value out of one,.Await(ct)/.ObserveCompletion(reportLateFault, ct). The original text is kept below so the record of what was recommended, and for how long, stays readable. See In-mesh test cases no longer continue on the portal's own threads (2026-09-18).
A test now awaits the observable directly under a timeout
( The only place a bridge may still work is inside an activity, where
nothing mesh-side runs after the await — and even there the reactive shape is preferred.await hub.DisposalCompleted.FirstOrDefaultAsync().Timeout(30.Seconds())), exactly as production
code composes and subscribes.