Given we are talking about IPv6 - my apologies I forgot ip route show defaults to v4 information ... If you could redo with ip -6 route show that'd be great...
Whilst testing (and in general) stick to /64 assignments - that is the expectation and best place to start ... and similarly either use a provided IP space (from a tunnel broker if need be) or use ULA to avoid edge cases there ... if that works then you can test outside the expected areas ...
With the behaviour you mention I'm curious as to whether an entry for the network is being entered into the table at all on the system the code snippet is run on versus the one where ip addr add is used...
As an example from my system after doing an ip addr add fc00::::17/64 dev eth0 the routing table looks like:
$ ip -6 route show
2001::/32 dev teredo proto kernel metric 256
fc00::/64 dev eth0 proto kernel metric 256
fe80::/64 dev eth0 proto kernel metric 256
fe80::/64 dev teredo proto kernel metric 256
default dev teredo metric 1029
Check before and after you have done your code snippet... You might find it'll work fine if you preconfigure the routing table with that subnet (or just add another ipv6 address on that subnet to have it done automatically that way)...
If no route for that network gets entered it may not be surprising not to be able to ping until the first machine has and the neighbour is discovered that way...
Are you also 100% sure you are not dropping any ICMPv6 packets between systems - no transparent firewalls or anything?