This is a typical syndrome with programmers. They simply have no real world commonsense. They can write 20,000 lines of utter gibberish, but can't think through even a simple real-world action. If they had to tie their own shoelaces they'd do so first and then try to put the shoes on.
Ian I think part of your perception is that you believe it's one programmer or one team. It's most likely a dozen different teams in a handful of different countries.
Team one has been told to enforce 2 factor authentication in the REST teir.
Team two has been told to implement the web UI components for it.
Another team has implemented the SMS gateway.
Another team has done the data access layer.
Another team has done the database changes and stored procedures.
Another team manages the interconnect messaging bus.
Another team has been told to make phone numbers mandatory on another part of the UI
Yet another team has tested part of it.
Yet another team has tested another part of it.
Finally another team did pen testing and vun testing and proposed changes back to all of the teams above.
Management and business didn't factor in the time to fix these security concerns and rushed them through, probably asking people to work until 11pm for a week!
All of them are working with partially complete requirements and test plans written by partially incompetent BAs. The Project managers and scrum masters who job it is to make sure changes synchronize across all the teams for a release are probably barely sentient.
So most likely the programmers all did what they were informed they were supposed to and only had a limited view of one or more parts of the overall solution. I can guarantee you that 90% of them never, ever looked at the public version of the website.
Someone somewhere dropped a ball, probably in final UAT testing. Or maybe it was a deployment issue.
With my lead developer hat on, I would guess what has happened is that the requirement for the two factor stated:
WHEN customer.PhoneNumber is NOT NULL or ""
But previously they had used the value {blank} in place of NOT NULL or "" for a version back in the past.
Nobody remembered this across all the teams and nobody tested it and ... BANG.