You're correct that it's hard to have readers see something separate from writers. It actually depends on an experimental feature that might just go away at any time.

In journal mode (which is what the VFS uses), the sequence for a write transaction is: (1) xLock(shared); (2) xRead(change-counter); (3) xLock(reserved) ...

The read of the change counter with the shared lock complicates things, because at that point we don't know if there will be a write upgrade to reserved.

However, the experimental feature makes it like this: (1) xFileControl(experimental-pragma); (2) xLock(shared); (3) xRead(change-counter); (4) xLock(reserved) ...

So you can distinguish shared locks that will be immediately upgraded.

https://sqlite.org/forum/forumpost/c4ca8e7f4a887aa4