I would argue a few things:
First: You need to be aware, in your program, of when you need to get data outside of your process. This is, fundamentally, a blocking operation. If your minor refactor / bugfix means that you need to add "async" a long way up the stack, does this mean that you goofed on assuming that some kind of routine could work only with data in RAM?
Instead: A non-async function should be something that you are confident will only work with the data that you have in RAM, or only perform CPU-bound operations. Any time you're writing a function that could get data from out of process, make it async.
The problem comes when you have a critical section where you need to hold a mutex (lock): If you're working with "proper" async code, you can safely call any non-async code from within the lock. (C# enforces this, because a lock statement can not contain the await keyword.)
When any method you call can block on IO, synchronous programming (IE, using the OS to become async), can leak and make you hold your mutex longer than you should.
---
That being said, many of us build our careers programming threaded code that relies on the OS to block. So at this point we're splitting hairs.
On the other hand, form a more abstract, theoretical level, it is important to know that there is almost always an event loop at some point deep in the stack and sync code is just sugar over async and you can always transform from one to the other.
Take something very common like cryptographic hashing, if you use something like node.js you really don't want to block the main thread calculating an advanced bcrypt hash. It also meets all of your requirements that data not come from outside ram and is very CPU bound.
Obviously, if you are directly calling this hashing algorithm you should know, however, the introduction of a need to hash is completely unpredictable.
I guess I implied quick operations when I said "CPU bound." (IE, calculating a square root, string manipulation, (de)serialization...)
I haven't done hashing in Node.js. I assume that the bcrypt API is async and calls into a native library?
If you write a lot of pure functions, in a Functional Core, Imperative Shell manner, then only the imperative part has to deal with any of the async parts. Yes it’s the topmost part of the code, but there is nothing to “infect” with it which isn’t already destined to be.
It’s when you try to write imperative code like there are no consequences for doing so that the consequences show up en masse and can be confused as symptoms of entirely different problems.