I kind of wish I didn't say "message bus" in that example, that sounds too enterprise-y.

In practice the use case I had in mind was the Google Search pipeline. Simplifying quite a bit, there is (or was, 15 years ago) a front-end server (mostly renders HTML), several back-end indexes (serving different corpora, like web, images, maps, etc.), and a middle part that fetches data from all the back-ends and serves them up to the front-end.

The middle part is where the problems would sometimes appear. A back-end index would be updated to stop filling in some field of a search result which had previously been required. They would dutifully update the front-end code that depended on the field before changing the back-end to stop sending it. But if they knew the middle part didn't use the field, then they often believed they didn't need to wait for the middle part to do a release -- forgetting that the `required` part is enforced everywhere.

The middle part wasn't a dumb message broker, it would actually inspect the data too, for a variety of reasons. Many ranking algorithms were implemented in the middle part and they might want to inspect pretty much any part of the information attached to search results. So your idea that the middle part should just treat all the "payload" as opaque wouldn't have worked -- it would have been hard to draw the line between what should be opaque and what shouldn't be, and impossible to keep it updated as requirements changed. The whole exercise would have just been a huge burden.

No, this situation is not at all unique to Google. It is, in fact, quite common in any arrangement that involves three or more independently-managed components.

> And so the power of Protobuf and Cap'n Proto schemas, particularly the power to validate messages which is supposed to be a primary advantage of strong static typing, is limited

I would argue that a much more important power of these systems is their ability to manage change. It's extremely hard to fully test what happens when two different versions of your code interact. Almost all automated test setups only test the current version of the code at HEAD; they rarely attempt to set up old versions of some services. Even if they do, how many combinations do you test?

The genius of Protobuf (which Cap'n Proto mostly copied) is that it's pretty easy to reason logically about how a change will interact with older versions of the code. You add a new field, you know old code will just ignore it, and new code receiving data from old code will fill in the default value. It's rare -- surprisingly rare, to be perfectly honest! -- that people can't reason through this in their head.

The problem with `required` was that the implications of changing it were not intuitive, because it's not intuitive that it had implications for servers that don't even inspect the field in question.

The lesson for me is that validation has to happen at the point of consumption. You should not try to validate your data early in the pipeline because your validation rules will likely become out-of-sync with what the consumer actually wants over time. The only way to maintain sync is for the consumer itself to decide whether the data meets its requirements. This makes a lot of theorists uncomfortable, but I've seen in play out in practice so many times...