Welcome to const and reference collapsing. When you have const T&, the reference gets applied to T, and so does the const. You call g like
g<int&>(n);
so you have specified that T is a int&. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& & becomes just int&. Then we get to the rule from [dcl.ref]/1, which states that if you apply const to a reference it is discarded, so int& const just becomes int& (note that you can't actually declare int& const, it has to come from a typedef or template). That means for
g<int&>(n);
you are actually calling
void f(int& a, int& b)
and you are not actually modifying a constant.
Had you called g as
g<int>(n);
// or just
g(n);
then T would be int, and f would have been stamped out as
void f(int a, const int& b)
Since T isn't a reference anymore, the const and the & get applied to it, and you would have received a compiler error for trying to modify a constant variable.