> Seems like properly written downstream code would deadlock if given an IO implementation that does not support concurrency.

No, it would fail with error.ConcurrencyUnavailable. See example 10 from TFA.

More to the point, this implementation decouples asynchrony from concurrency. In GP's example of a microcontroller blinking an LED, there's no explicit requirement for concurrency, only asynchrony. That is, it would be nice to be able to do other things while we wait for the LED controller to potentially time out, but it does not fundamentally change the application logic if the program blocks until the function completes. If you use io.async to run the call, then it will do exactly that: run other code while waiting for the controller if a concurrent Io implementation is passed, and block until the controller returns if a synchronous Io implementation is passed.

Functions that require concurrency would, however, need to be documented. Several people have proposed adding a feature like Rust traits or C++ concepts to Zig that would enable you to annotate type signatures to indicate which features need to be available for a generic substitution to succeed, but until such a thing exists, you're pretty much best off reading the source itself. In practice, most code probably doesn't require concurrency, and library authors are free to sprinkle asynchrony everywhere without worrying about whether or not their users' Io implementation will actually support concurrency.