Trying to accommodate the complexity you describe ahead of time could well be its own mistake. One thing I've learned in the trenches is to wait for most things to prove to be a problem before adding complexity to address them. I believe you that there are cases like you and the OP describe, where "all sync or all async" is a good invariant to have. But I don't believe it's a general rule, the alternative to which is doing it wrong (or even the devil, as in the OP).
Another thing one learns in the trenches is that almost all general rules about software are bogus and end up distorting one's thinking. It's better to choose invariants on a system-by-system basis.