Linux is weird.
Other operating systems that guarantee ABI compatibility, such as Windows, do it by shipping shared libraries on the box that form the OS’s ABI. The syscall numbers themselves change between versions plenty often. Most operating systems, like FreeBSD and macOS, work like this. The only remaining ones are with no ABI guarantees at all, like, I think, OpenBSD.
Linux, on the other hand, is the exact opposite of Windows. The kernel has a very hardcore ABI compatibility guarantee — if it’s marked as stable, it stays, no matter what. But a lot of userland stuff, even pretty core stuff like init.d, change every five years or so. And some Linux distributions, like Android, are completely incompatible with the normal GNU userland.
This is probably responsible, in part, for the popularity of statically-linked binaries like Go-lang produce, since it’s about the only way to really take advantage as a software distributor of the ubiquity of Linux-based servers.
How do statically linked binaries help with init.d change?
Things like glibc do take backward compatibility very seriously, you can take advantage without static linking. PEP 513 is a good example of Linux ABI compatibility in action.
NetBSD does this too. It’s not so grim though. When we want to change a struct we make a new syscall and have a small shim so the old entry path uses the new code. It’s obviously more complexity but it’s not far up the list of the worst offenders.