*args is bypassing arguments without any conversion. It looks like ruby converts last hash to keywords and than converts it back to hash. I think it is a bug.
This behavior is expected. The positional hash argument is converted to keyword arguments when kw is called. That is not going to work in Ruby 3 (see #14183), hence the warning.
For delegating argument to a method that accepts keywords, you should probably use ruby2_keywords (if you also need to support older ruby versions):
This variant is wrong with ruby 2, because it provides:
non kw {:a=>2}
kw 2
warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
warning: The called method `non_kw' is defined here
non kw {}
kw 3
non kw {}
kw 1
As mentioned earlier, you should probably use ruby2_keywords. In this particular case, even if you don't want to support earlier Ruby versions, because you don't want the positional hash argument being interpreted as keywords by non_kw.