Function’s methods being involved in world age isn’t new, this following example is from v1.10 and works all the way back to v0.6 with slightly different error messages:
julia> function define_method()
@eval bar() = 1im
println(@eval (bar()))
bar()
end
define_method (generic function with 1 method)
julia> define_method()
0 + 1im
ERROR: MethodError: no method matching bar()
The applicable method may be too new: running in world age 31548, while current world is 31549.
This odd semantic was introduced because compiler optimizations can only consider the state of a function’s methods at that point in time, prior to execution changing that state. @eval and @invokelatest sacrifices those optimizations in order to consider the updated runtime state. If you don’t want to @invokelatest every call-site to dodge world-age, there are ways to dodge defining new methods or global names entirely.
Compile-time state had also applied to global constant variables because optimizations can bake in values and compute at compile-time. Prior to v1.12, reassigning global constants (where possible) would only warn you of silent errors because methods won’t adapt (invalidation of obsolete code). Now that they’re part of world age, methods do track them and adapt. There’s also no real distinction between reassigning global constants and struct/function names; struct and function names have always been implicitly const. However, struct definitions only reassign the name if the fields are different, while method definitions don’t under any circumstance.
Your original example actually doesn’t involve reassigning global constants, it changes global names of an external module by declaring new variables, whether const or not. This being involved in compiler state seems new, but I’m not sure because I haven’t really done intermodule global declaration/assignment before.