I would separate the routing question from what is actually choosing the address, because on a NAT64 carrier the choice happens before routing matters.
On Jio/Airtel the handset network is IPv6-only with DNS64. When the client resolves your internal service through the carrier resolver, that resolver synthesises an AAAA in 64:ff9b::/96, and normal address selection then prefers the IPv6 answer over the A record. The request leaves over the carrier's IPv6 path, reaches your service from the carrier's NAT64 translator address, and your IP whitelist correctly rejects it with 403 - while curl -4 works because it forces the A record and therefore the tunnel. That also explains why the ip6tables DROP on FORWARD for 64:ff9b::/96 changed nothing: those packets never touch your server.
On your question about block-ipv6 specifically, that option is not a filter for traffic that stays off the tunnel. The manual is explicit that it only means anything if IPv6 traffic is actually routed into the tun interface, and the documented client-side combination is ifconfig-ipv6 plus redirect-gateway ipv6 together with block-ipv6. Without an IPv6 address and an IPv6 default pointing at the tunnel, block-ipv6 has nothing to answer and the carrier's IPv6 route stays the best path, which matches what you observed in tests 1 and 2.
So there are two places to fix this, and in my experience the DNS side is the more reliable one:
First, make resolution happen inside the tunnel. If the client still queries the hotspot's resolver for that name, you will keep getting a synthesised AAAA regardless of routes. With systemd-resolved on Ubuntu 22.04 this is common, since per-link DNS can keep the hotspot resolver for queries that are not scoped to the VPN's search domain. Check resolvectl status and resolvectl query <service> while connected and see which resolver answered and whether an AAAA came back at all. If the internal names are served by your own DNS with A records only, and that DNS is used for those names, there is no NAT64 address to prefer and the problem goes away without touching IPv6 on the server.
Second, if you also want route-level enforcement, the client needs an IPv6 default in the tunnel rather than only IPv4. Before changing anything, capture ip -6 route on the client while connected: if there is no ::/0 or ::/1 plus 8000::/1 via tun, nothing you push about IPv6 is being applied.
One correction to the redirect-gateway versus redirect-private comparison: the def1 flag only rewrites the IPv4 default, as 0.0.0.0/1 and 128.0.0.0/1, and redirect-private is documented as behaving like redirect-gateway while omitting the default gateway change. Neither one suppresses IPv6 unless the ipv6 flag is present, so whatever was keeping IPv6 off the picture on 2.8.5 was almost certainly a different part of that push or of the old server's IPv6 configuration, not def1 itself.
To make that concrete rather than inferred, the useful pair to post is the complete PUSH_REPLY from both versions side by side, plus ip route and ip -6 route from the same client on each. Two questions that decide which of the two fixes is even available to you: are the internal names served by your own DNS, and is that DNS reachable only over the tunnel?