I have a question about the desirability of stateful metaprogramming in general. From CWG 2118 ("Stateful metaprogramming via friend injection") I made a conclusion that it is not something we would like to have, but the paragraph 3.15 of P2996 demonstrates how this proposal makes it easier to implement a compile-time counter.
I'm worried about this. Firstly, because if the standard mandates that the compiler state is visible somehow to the user, then it should specify observed behavior. But it's hard due to the freedom compilers have in some areas. The typical example is the point of instantiation of template function. Let's consider the following program (https://godbolt.org/z/4aajT1fvj):

template<typename>
struct TU_Ticket {
  static consteval int next() {
    ...
  }
};

template<typename T>
int f() {
    return TU_Ticket<T>::next();
}

template<typename T>
int f() {
    return TU_Ticket<T>::next();
}

int g();

int x = f<void>(); // #1
int y = g();           // #2

int g() {                // #3
    return TU_Ticket<void>::next();
}

int main() {
    std::cout << "x=" << x << ", y=" << y << '\n';
}

The output produced by EDG is "x=1, y=0" and it demonstrates the fact that the definition of 'f<void>' is instantiated below call of `f<void>()` (#1) and call of `g()` (#2) and even the definition of `g` (#3).
The standard cannot specify it, because we don't want to define strictly at which point the definition of template function is instantiated. So the behavior of this program will be unspecified? Is it fine?

The second reason why I don't like to make the compiler state observable by the user is that it causes problems with any kind of lazy or partial parsing. For instance, fast module interface parsing, or body-skipping in an IDE-centric parser, and so on.
Let's consider the following source file:

struct TU_Ticket {
  static consteval int next() {
    ...
  }
};

void a() {
    TU_Ticket::next();
}

std::integral_constant<int, TU_Ticket::next()> b();

Note that function 'a' is non-inline, non-constexpr, doesn't have a deduced return type. It means that the definition of 'a' doesn't affect the "interface" of the file. (The term "interface" could be interpreted in different senses, like "C++20 module interface" or "set of symbols which are declared in the file and should be processed by IDE or some indexing tool like clangd".)
So it's tempting for lazy parsers to skip the body of 'a'. But it leads to evaluation of the return type of function 'b' to 'integral_constant<int, 0>' instead of 'integral_constant<int, 1>' like a normal compiler will do.

Also, I see the similar issue with proposed `std::meta::define_class`. Without doubt, it's handy functionality, but it modifies the compiler state, and the proposal doesn't define or limit somehow the context where this function could be called. So I'm afraid it will be called in some contexts which are usually skipped by lazy/body-skipping parsers.

--
Andrey Davydov