new(obj) → new_hash
If obj is specified, this single object will be used for all default values.
Now Hash.new([]) is holding the default Array object. Now b[:a][:b] << 'hello' you are entering, the "hello" to the default Array.The default value is being returned, when the key doesn't exist in the Hash.
Don't think you are adding keys to the Hash objects, with this b[:a][:b] << 'hello' line.
b[:a] is giving the default Hash object, which is Hash.new([]). Now on this Hash object you are calling Hash#[] using the key :b, but as :b is the non existent key, it is giving the default Array object.
That's why b, b.size and b.keys all are proving that Hash is empty.
Finally.
Why is that I can access the value stored at b[:a][:b] yet b has a size of 0 and no keys?
Because, you added the value "Hello" to the default Array, as I mentioned above. That value is coming when you are using the line b[:a][:b].