Software is like an onion. Your team’s code is one “layer” in this onion. There are layers below you (which you rely on), and layers above you (which rely on you).
Of course, unlike an onion in real life, all the layers in this onion are continuously changing. New features, bug fixes, performance optimizations, etc.
In a good architecture, the effect of change flows in exactly one direction: up. You can only break layers above you, not below. This implies that the deeper you are in the onion, the greater the responsibility. Any little change can ripple upward in unexpected ways, because there’s a deep intertwining–a dependency.
It’s also like the princess and the pea; even the tiniest change can make stuff higher in the stack uncomfortable; you never know what behaviors / bugs / etc. the upper layers are relying on.
You can try to avoid breaking stuff at compile time (e.g. changing an API in an incompatible way). Beyond that, you can also run all the unit tests, get code reviews from peers and/orrelevant dependent teams, etc. Isn’t that good enough?
Alas, no. The nature of human fallibility is, things aren’t perfect, and if you plan for them to be perfect, you’ve made an imperfect plan. There will always be bugs, and bugs in lower layers can reach WAY up the stack to hose features and team way above them. This is true of everything even hardware: remember the Intel Meltdown and Spectre bugs?
The only “bullet proof” world is one where teams and services are totally independent.
Unfortunately, this isn’t possible when you have to share. Which we all do of lots of stuff. Housing and hosting, network, VMs, Containers, DB schema’s, Development stacks or even Amazon solutions.