I was reading a design patterns book. I got to the UML class diagrams — and I stopped.

Because the diagram on the page was describing something Rust already says in its own syntax. A struct is a class. Option<T> is a 0..1 association. Vec<T> is 1..N. Ownership is composition. The formalism I was looking at, drawn as boxes and diamonds, was the same information the compiler already had — just in a different notation.

Which led to an uncomfortable thought. If the type system already encodes what UML draws, then translating my code into UML shouldn't tell me anything new. It should be redundant. Unless the translation didn't line up — and everywhere it failed to line up, there would be a bug hiding in the gap.

So I tried it. I took Runique — my Rust web framework, v2.1.21 — and I modeled the framework itself, module by module, in UML for structure and Merise for the data. The intuition was mine; I used Claude to help verify each translation against the actual code, line by line. We found twenty-plus latent bugs. Three of them were security-relevant. None of them had shown up in cargo test, in tracing, or in the compiler.

This is what the gaps looked like.