Our whole practice revolved around not pushing broken code because all code was tested locally prior to the push. In fact we practiced continuous integration as in its original meaning, integrating code multiple times per day. Releases were performed from a release branch so the occasional hiccup wasn’t worse than let’s say a PR that does not build. However fixing the broken build was the TOP priority if it happens (like every two months)
With good infra, everything from unit tests to integration to acceptable tests get ran before code hits main.
The only excuse for builds breaking nowdays. is insufficient automated safeguards.