Even AST-based macro systems have tricky problems like nontermination and variable capture. It can be tough to debug why your compiler is stuck in an infinite macro expansion loop. Macro systems that solve these problems, like the R⁵RS syntax-rules system, have other drawbacks like very complex implementations and limited expressive power.
And often there's no easy way to look at the code after it's been through the macro processor, which makes bugs in the generated code introduced by buggy macros hard to track down.
By contrast, if your code generator hangs in an infinite loop, you can debug it the same way you normally debug your programs; it doesn't suffer from tricky bugs due to variable capture; and it's easy to look at its output.
AST macros are complicated, yeah, and I agree that any half-decent macro system needs a convenient way to dump generated code and so forth. I'm not saying any macro system is better than codegen. But a decent macro system will give you hygenic tools to modify an AST, whereas codegen really forces you to hack something together. I'll grant that there's some worse-is-better charm to codegen, but I don't think that saves it from being ultimately worse.
Writing a compiler is not "worse is better" and does not force you to hack something [fragile] together. Therefore, your argument is wrong.
Frankly, an official Go codegen library would solve pretty much all my complaints, but the only difference between that and a macro system is compiler integration.