>reasonable worst-case behaviour (think real-time apps, or adverserial scenarios)
I'm not sure I agree. When faced with potentially adversarial input, a hash should be keyed. And, depending on the specific tree, you can probably cause a lot of havoc by causing repeated tree reorganizations. Even worse, you have a timing side-channel, because node-split and node-merge are expensive, likely measurable over the network. This can leak info about existing adjacent keys in the database.
This kind of attack is afaik not as researched or well-known as hash collision based attacks, but in my book that is a point in favor of hash tables with keyed hashes.
On the other hand, both approaches shouldn't play in the same league: If you need to support range queries, then you need to support range queries.
>And the speed boost from locality gets more dramatic every passing year as the memory gap keeps widening.
This is true for scenarios where trees save cache misses (e.g. if there is a correlation between order of queries and location of keys). The linked comparison explicitly compared L3 misses between various trees and various hash tables for various scenarios, and the hash tables come out better in that metric.
All that being said, ART is pretty cool and node16's branch-free SIMD search is amazing.