The root cause is that WsRun() (ws.go:96) always uses cc.client.Remote() — the single node that RPC picked — for the websocket connection. When that node's WS fails but its RPC works, newRpc() picks the same node again next time.
NoRPCEndpoints is not triggered in this case: evaluateNoRPCEndpointsAlert only checks cc.noNodes, but newRpc() sets cc.noNodes = false on RPC success, so the counter keeps resetting.