I think you could write concurrent spaghetti code in any environment just as easily, to be honest. I also think it really depends on which actor-model implementation you're using. Each offers their own unique experience, as I've found that there's a noticeable difference in the Scala+Akka approach vs Elixir+OTP, for example.
The actor model is just one way of reasoning about concurrency. Your mailbox serializes/linearizes your interactions so you don't necessarily need locks. Because you get that for free, you can write "single-threaded" code to handle each message. Messages can be sent across a network, so now you can concurrently interact with remote actors too. The simplicity of the model stops there.
Concurrent code gets complicated very quickly by nature. If you architect your application to have messages causing ripple effects in your system, your application behavior is going to be very difficult to reason about. But that's nothing new, either. Instead of sending messages, concurrent function calls could produce the same issue.
Is reasoning about message flows and behaviors hard? Yes, but that's just a byproduct of concurrency. Like you said, "programmers simply need to use discipline", but everyone will disagree on what discipline looks like. Each actor model implementation will have their "best practices" to mitigate the complexity of concurrent interactions, as will each organization using said implementation for their project. At my work, the way we use Scala+Akka was very structured and not at all the way I expected, having been used to Elixir+OTP.
As I think the issues of the actor model are actually issues with reasoning about concurrency in general, I would pick actors over coroutines just for the up-front structure and simplicity it provides.