I can't imagine deploying a functionality that needs to interact with 20 other services, if I can't have some zero-cost assurances like Go's typing and having all IDL available at developing time. This is of course is even better if at compile time I can check all contracts are still honoured. Monorepo is a really "cheap" way of getting all this for, close to, free.
If a product feature X can't be delivered without changes to 20 services, the architecture is too granular.
But the ~main whole point of defining distinct services which exist on different ends of a wire is so that they don't need to stay in sync at the code level!
As you say, a service implements a contract, written as an IDL or a JSON schema or informal convention or whatever, in order to express a promise to consumers. That promise needs to be kept as long as any consumer relies on it. If your search service publishes a protobuf that has a service definition called e.g. SearchV1, then your search service is absolutely obliged to keep supporting that SearchV1 service until it's no longer used by anyone.
If this isn't the case, and you can deploy changes to a service that violate the wire-protocol contract you establishes with your consumers, then this is a problem. And it's easy to do. I find that many programmers don't fully understand the weight and implications of the interface they define between client and server.
What you say is also true