Clean disassembly can be extremely hard for some games, and not always do what you want anyway.

I mean sure, it is always possible to dump out "something" that can reassemble to the original if you don't change anything. It is less easy to get everything correct such that if you change the length of a code block or some data array the rom still fully works. This potentially requires having properly identified all the code vs data, and all data that contains static pointers to other data (including immediate instruction operands) and replacing them with labels. But on some systems that is still not too hard.

On others it is terrible. For example the SNES where instruction sizes vary depending on the accumulator or index register mode sizes. This along with occasional use of non-standard flow control (like subroutine calls that never return, but instead pop the return address off the stack, and use it to find a jump table that occurs right afterwards), makes most attempts at automated disassembly fail. Semi-automated disassembly guided by information about instruction widths from an emulated playthrough helps, but getting such traces for all the code in a game can be really difficult.

Even if you do end up with a completely accurate disassembly, significant changes are not always easy. SNES ROMs code banks may have little room remaining. Subroutines that can be called cross bank are different from those that can be called in the same bank, and there is very much visible differences to the assembly for cross bank data access vs "current bank" (which is not always the same as the current code bank). Assemblers that do the right thing here don't really seem to exist, and would be based on fallible heuristics that will silently misassemble in some cases leaving you with a crash.

While obviously nothing is insurmountable here, it does mean that using ROM Hacking style techniques to avoid disturbing the bank layout can sometimes be easier than making the change you want, and then trying to shuffle things so that your new code will still fit.

Things get even worse if you want to maintain glitch level compatibility with the original game (as is common for things like practice hacks for games that have glitch speedrun categories). Some glitches very much depend on out of bounds data accesses returning a specific value which happens to be some code, or a specific value in some later table. It can be difficult to preserve those while allowing code and data to be relocated. (Other glitches don't always require these sorts of things, and Nintendo has accidentally preserved many glitches in some games while porting from assembly to C.)

I will admit that the SNES is MUCH, MUCH worse than most other consoles in the sort of headaches I describe above. Most other consoles tend to have an unambiguous disassembly that can be far more automated, newer console tend to avoid having near/far pointers and near/far subroutines, etc. The glitch compatibility considerations still apply though.

I'm not arguing against full reverse engineered assembly of games, that can be wonderful. And starting from those can be a great way to develop a hack on some systems. But it hardly obsoletes traditional rom hacking, which can require much much less effort to get started with, and for some scenarios may be the better fit even with a complete disassembly available.