>We ended up adding the APIs back and creating a hurried release to fix the issue.
So it was entirely possible to keep the software working with these. Why change/remove them in the first place? Is the benefit of of the new abstraction greater than the downside of requiring everyone using the software to re-write theirs?
I think this is a valid question for this specific case, but may not always be possible. That said, I think as a user I would probably prefer it if under the hood the old function called the new so they can deprecate the behavior without breaking the API. In that way you can still emit the deprecation warning while also only having one actual code path to maintain.
OS software maintainers don't like maintaining legacy ugly APIs forever and want to refactor/remove legacy code to keep themselves sane and the project maintainable.