A full spec is indistinguishable from code though.
That's the bottom of the problem. You can think all you want in your spec doc, you won't fully solve all the problems that you will face during implementation.
That's why ports are easy with LLMs, cause the code implicitly carries all the spec.
Sure, there may be a gap between the code and the idea behind the spec, but it can be argued that the gap between the spec as a document and the idea behind the spec is just as wide, and in fact doesn't take into account the constraint of reality.
LLMs generally suck at taking the initiative. Tell it to build a report, it's going to do it, but then you'll have to iterate a lot to make sure it's producing it the exact way you want it.