Best practices for clean role separation in multiplayer (c++)?

I don’t know the “right” answer, but i can share a bit of personal experience:

Sprinkling authority checks throughout an actor seems inadequate

We(team of 3 devs) have started developing as a dedicated-server-only game and authority checks was manageable approach to some extent.

it gets more complicated if you want to support both dedicated servers and listen servers

But here you are absolutely right, the real sht started a year after when we decided we need a listen-server support as well. At this point i was still sometimes missusing HasAuthority() (hell, i’m even now not really able to tell all the corner cases of the top of my head), so we moved to custom side checks named ShouldRunServerLogic(), ShouldRunClientLogic() & etc.
Aand, it’s appeared this approach for us was way more manageable than default one: no need to remember authority’s corner cases, just keep in mind which side you want to be executed on. We did managed to add listen server support without much pain this way.

(Internally those functions are just switches over GetWorld()->GetNetMode() value)

With this, we using no extra conventions on top of it, as such parts of code are quite a self-describing and 90% of code will have all the shared\server-only and client-only parts you mentioned.