> just consider what happens if GUARD takes the name as an argument,

The name token will be assigned the edition of the originating position.

#pragma STDCXX EDITION 2023
#define GUARD(var) auto var = make_guard()
#pragma STDCXX EDITION 2020
GUARD(_);
GUARD(_); // `_` is a normal identifier, so this will probably error.

> or if an expression is constructed by putting two macros with different editions next to each other.

Let's replicate the removal of implicit conversions from the Epochs proposal then.

#pragma STDCXX EDITION 2020
#define MOVE move
#define LPAREN (
#define RPAREN )
#define COMMA ,
#define P p
#define LIT_3_42 3.42
#define LIT_2_49 2.49

#pragma STDCXX EDITION 2023
void move(Particle&, float x, float y);

void foo() {
Particle p{};

// error, all tokens are in the 2023 edition
move(p, 3.42, 2.49);

// depending on the proposal, at least one of them
// should work because all constituent tokens for
// the call expression are in the 2020 edition.
// proposal authors would then be responsible for
// which tokens are considered "constituent" here.
move LPAREN p, 3.42, 2.49 RPAREN;
move LPAREN p COMMA 3.42 COMMA 2.49 RPAREN;
MOVE LPAREN p COMMA 3.42 COMMA 2.49 RPAREN;
MOVE LPAREN P COMMA LIT_3_42 COMMA LIT_2_49 RPAREN;

// assuming the call only regards `(` and `)` as
// constituent tokens, the following call has
// ambiguous editions and will fail to compile.
move(p, 3.42, 2.49 RPAREN;
}

So my chain of logic is that, we ideally want to put editions to the AST, but the existence of textual inclusion means that edition should also exist in tokens and the AST node's edition will have to be computed from them. Not a big deal for existing compilers (they already track spans).

> what happens with headers that don't care about editions, and only begrudgingly even include an extern "C" for C++ users?

For this reason I believe the edition should reset across files, reverting to the default edition.

And in fact this feature will benefit both C and C++, and thus ideally be harmonized. In this way we will no longer have to special-case some files to be implicitly in the `extern "C"` block! (Yes, this exists, see for example -internal-externc-isystem in clang cc1.)

> Suppose you wanted to remove most vexing parse in a new edition: changing the result of `Foo bar(std::array<int, PAGE_SIZE>())` is the goal!

Now this is probably a better question, because we have tons of options for how existing parsers should behave. Note that I've intentionally omitted this part because those options are only useful when the ambiguity arises, and I think they can be determined in the case-by-case basis.

But if you indeed want to remove the most vexing parse, it's mostly up to the proposal author's decision. I should note the following quote from ISO C++:

If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not apply. The whole statement might need to be examined to determine whether this is the case. [1]

So the parser should have already produced two possible ASTs for the same token sequence in the first place and picked one of them, in principle. The proposal therefore will determine which token affects this decision---for example that may be `(` and `)` as in the call, or the whole `std::array<int, PAGE_SIZE>()` sequence that can be parsed as a type-id. In any case the proposal will give a concrete and compatible algorithm to remove the most vexing parse in a new edition. You can't remove it in existing editions, and this is by design.

(Alternatively and probably more commonly, the parser may use a prioritized choice, i.e. trying to parse type-id first then initializer-clause if it fails. In this case parsing type-id may have to signal that some constituent tokens are of a new edition and backtracking might be needed. The proposal author would want to experiment with different choices of constituent tokens to ease the implementation. But again, parser should have already implemented backtracking so this should be not a huge cost.)

[1] https://timsong-cpp.github.io/cppwp/n4868/stmt.ambig (this is not exactly about the most vexing parse but both cases are using the same wording)