← all articles

The Prototype Was Never The Spec

The Prototype Was Never The Spec

Watched a team lose most of an afternoon this week building a screen that nobody had actually asked for. Not because anyone was careless. Because a prototype had a field on it, someone found the field, and from that point on the field was real. Nobody had gone back to check whether the person who owned the requirement had ever intended it to be there. The prototype had quietly become the spec, and the spec it replaced was sitting one click away the whole time, unread.

This happens more now than it used to, and the obvious reason is AI-assisted development. Ask a coding assistant to build out a feature and it will happily fill every gap you didn't specify, because a working screen needs values in every field and a sensible person filling in gaps will invent something plausible rather than leave it blank. That invented plausibility is the trap. It looks exactly like a decision. It has the shape of a decision, the visual weight of a decision, sitting in a mockup or a generated repository looking every bit as authoritative as something a product owner signed off on. But nobody decided it. Someone typed a prompt, got a result, and moved on, and three weeks later a developer opens that result treating it as ground truth.

The instinct to trust what already exists is not a bad instinct in general. Most of the time, reusing what's there is exactly right — I'd rather see a team extend an existing menu than invent a parallel one for a problem that's ninety percent the same shape. The failure mode isn't reuse. It's reuse without provenance. Before you build on top of something, you need to know why it's there: was it specified, was it inferred by a generator, was it copied from an earlier draft that got overtaken by events? Those three things look identical in a diff. They are not identical in how much weight they should carry.

The tell, in the case I watched this week, was almost comic once it surfaced. Someone pointed at a field on a generated screen and asked where it came from. Nobody could say. It wasn't in the ticket. It wasn't in the acceptance criteria. It existed because another screen referenced it in passing, and a generator, doing exactly what generators do, filled in the referenced thing so the reference wouldn't be broken. The actual story, when someone finally reread it, only ever talked about data records — there was no mention of a screen for it at all. An entire configuration page had been conjured into being to service a field that may not have needed configuring by a human at all, because the data behind it already lived somewhere else, in a system nobody had asked.

None of this is really an argument against using AI to generate code, prototypes, or scaffolding. It's an argument for treating what comes out of that process the same way you'd treat a strong opinion from a smart but uninformed colleague: worth listening to, not worth executing on faith. A generated implementation is evidence of what's plausible, not proof of what's required. The two get conflated because a working screen and a correct screen render identically. You cannot tell the difference by looking. You can only tell the difference by asking someone who actually owns the answer.

That's the part that's easy to skip under delivery pressure, because going back to ask feels like it's slowing things down. In practice it's the fast path. The team that kept building on the invented field would have shipped a screen, then discovered in review that the underlying data already existed somewhere else, then had to decide whether to rip the screen out, repurpose it, or leave two sources of truth for the same fact indefinitely. That last option is the one that quietly costs the most, because two sources of truth doesn't fail loudly. It fails as a slow accumulation of small inconsistencies that somebody, much later, has to reconcile by hand, usually under worse time pressure than exists right now.

There's a useful discipline hiding in this, and it's not complicated: every time you're about to build against something that already exists in a prototype, a mockup, or generated code, ask what kind of artefact you're actually looking at. If it traces back to an explicit decision, build on it with confidence. If it traces back to an inference — a generator filling a gap, an earlier draft nobody revisited, a screen someone built because a related screen referenced it — treat it as a question, not an answer. The five minutes it takes to ask "did we actually decide this, or did something just assume it" is cheap. The alternative, discovered after the feature is built, almost never is.

The commercial reality makes this sharper, not softer. Time spent building the wrong screen isn't neutral — it's time that could have gone toward the four or five things that actually mattered for the release, and it's a screen someone now has to unwind, explain, or maintain regardless of whether it should exist. Good engineering judgement here isn't about mistrusting the tools. It's about noticing that a tool filling in a plausible gap and a person making a real decision leave the same shaped trace in your codebase, and only one of them is safe to build a business on.

I don't think this gets easier as these tools get better, either. A better generator produces more convincing gaps, not fewer of them — the whole point is that the result looks intentional. Which means the checking habit matters more precisely as the tooling improves, not less. The question worth asking isn't whether the screen works. It's who actually asked for it, and if the honest answer is "nobody, it just showed up," that's the moment to go find the person who can tell you whether it should stay.

Matthew Ratcliffe, software developer and architect, Ballarat
Senior Software Engineer & Architect

20+ years across the technology stack — from greenfield builds to brownfield rescues. Based in Ballarat, VIC, focused on AI, healthcare and high-risk data systems. Full resume →

Share your thoughts