"I told you the abstraction had two implementations. It has one. The seam is still right — the sentence describing it was a plan wearing the grammar of a fact."
What the Earlier Lesson Promised
Four lessons ago the engine's single abstraction was justified like this: generation genuinely happens in two different worlds — local weights on your own GPU, and a closed-weight vendor over HTTP — and that real fork is what earns the one Adapter boundary. Two implementations, one narrow interface, no other top-level seams. It was a clean argument, and the axis it picked was the right axis.
What Actually Shipped
The closed-weight capability did arrive. It did not come through the seam. It shipped as a separate subsystem with its own routes, its own request schema, its own history store, and its own vocabulary — sitting beside the adapter spine rather than behind it. The abstract base class still carries a docstring reserving the API implementation for a version number the engine has since shipped past, and the engine's own inspection endpoint returns a single adapter with a note admitting the divergence in writing. So the engine's one abstraction has, today, exactly one implementation.
Why the Second World Couldn't Wear the Shape
Look at what the interface actually asks for. It asks an implementation whether it supports a model row. It hands the run a progress emitter and a job record, and expects the run to write back which seed it actually used once the recipe's random seed was resolved. Those are job-lifecycle nouns, and every one of them came from the local path: a queued GPU job that streams progress, resolves a seed, and can be cancelled mid-step.
Now look at what a vendor call is made of: a provider, an aspect ratio, a resolution tier, a list of reference images — and, not a request field at all but impossible to design around, a per-call cost. No model row. No seed. No steps to emit progress against. Two requests that overlap in a single field — the prompt, and nothing else — cannot share a method signature unless one of them fakes most of it — which is precisely the wide-interface failure the narrow-boundary lesson warned about, arriving through the back door because the interface got wide after the seam was drawn.
The Dates Say Day One
One thing to be exact about, because it changes what kind of correction this is. The engine shipped its abstract base class with only the local implementation behind it, and shipped the closed-weight subsystem separately, both in the days before this quest was published. Nothing drifted. The lesson was describing a plan on the day it went out, and it took a cold reviewer reading the directory to notice. A claim that was never true is not evolution — it is a correction, and the honest thing is to say which one you are reading.
So Is This Dead Surface?
The quest has a rule for exactly this situation, and it is about to be used against the quest's own architecture. Concrete-first says an abstraction whose variation no longer exists is dead surface: delete the enum that holds one value, collapse the router that routes to one place, re-introduce the seam when a real second case lands. By that rule, a one-implementation Adapter is a deletion candidate.
It survives, but not for the reason the docstring suggests — and that difference is the sharpest thing in this lesson. The discriminator from the narrow-boundary lesson is this: a speculative abstraction has one implementation and no concrete plan for a second; a reserved seam has one implementation and a named, currently-maintained second one.
Apply it honestly and the API reservation fails. It is named for a version number the engine has already passed, in a docstring nobody updated, while the current architecture notes describe the closed-weight divergence as deliberate and say the adapter would be reconsidered only if some future client actually needed the job interface. That is a conditional, not a plan. The API seam is a reservation that expired without anyone announcing it.
What keeps the abstraction alive is the other reserved implementation — the one this quest already taught you about, two tracks back. Local video is reserved by interface in the ceiling matrix, and it is still named as its own adapter class across the engine's current architecture notes, with a stated reason: video's memory and time profile differ enough to need a separate implementation. That reservation is live. So the seam stays — carried by video, not by the API case that everyone, this quest included, kept citing.
What the Original Argument Got Right
Almost all of it. One real axis of variation, one abstraction, nothing else pluggable — that discipline held, and the engine still ships no second top-level seam. The bet on where to cut was correct. What was wrong was the tense: describing a planned implementation in the present, as though the bet had already paid out. The lesson claimed a fork that was only ever a plan, and the plan has since lapsed without a funeral. That's not an architecture error. It's a reporting error — and reporting errors are how a codebase and everyone's picture of it drift apart while the code sits there being fine.