"Every abstraction is a bet that something will vary. Make the bet only where variation is real — and the engine has exactly one real bet."
Abstractions Are Bets, Not Decorations
An abstract base class, an interface, a protocol — each one is a claim: "there will be multiple implementations of this, and code above it shouldn't care which." When that claim is true, the abstraction pays for itself. When it's false — when there's only ever one implementation — the abstraction is pure cost: indirection you read through, a seam that does nothing. The discipline is to make the bet only where you're confident variation is real.
The Engine's One Real Bet
Look at the engine and ask: what genuinely varies at the top level? Not the VAE — that's a module, varying inside the pipeline. Not the sampler — also internal. The thing that varies at the top is where generation physically happens:
- LocalAdapter — runs PyTorch and diffusers against model weights on your own GPU.
- APIAdapter — calls a closed-weight vendor (an external image service) over HTTP; no local weights, no GPU.
These two are genuinely different worlds — different failure modes, different latency, different everything. That difference is real variation, so it earns the one abstraction the engine ships: the Adapter.
What 'Narrow' Means
The Adapter boundary is narrow in two senses. First, it's the only top-level abstraction — there's no parallel hierarchy of abstract routers, abstract stores, abstract anything. Second, the Adapter interface itself is small: take a request, run it, return result bytes plus metadata. A narrow interface is easy to implement correctly, easy to reason about, and hard to leak through. Wide interfaces accumulate methods until every implementer must fake half of them.
The Future Adapters You Don't Build Yet
The Adapter abstraction also makes the reserved seams from the ceiling matrix concrete. A future VideoAdapter (local video) and a future video-API adapter both fit the same boundary — when video's day comes, they slot in as new implementations of the existing abstraction, no boundary change. The one bet you made on 'generation location varies' already covers variation you haven't built yet, because you bet on the right axis.