@kjpus got me on the path to finding this with the specific mention of dependent name, but he didn't submit in the form of an answer so I am putting the answer here explicitly.
So this is due to dependent name resolution and is explained quite clearly on cppref with an example well aligned with my original example code.
Non-dependent names are looked up and bound at the point of template definition. This binding holds even if at the point of template instantiation there is a better match:
#include <iostream>
void g(double) { std::cout << "g(double)\n"; }
template<class T>
struct S
{
void f() const
{
g(1); // "g" is a non-dependent name, bound now
}
};
void g(int) { std::cout << "g(int)\n"; }
int main()
{
g(1); // calls g(int)
S<int> s;
s.f(); // calls g(double)
}