Or: the SDLC doesn't fail at the stages. It fails at the handoffs.


The stories below are composites. Names, products, and companies have been removed, blended, and shuffled across two decades of shipping software. If you think one of them is about your company — that's the point.

The Control

A customer comes with a request. Simple one, on paper: "Give us a control that defines who accesses what."

So we build access control. Enforced at the moment of action. User selects a file, picks recipients, hits the button — the system checks permissions and blocks anyone who shouldn't be there. The ticket is satisfied word-for-word. Tests are green. Demo goes fine. We ship.

The customer comes back: "This is not what we asked for. We don't want an error after the button. We want it when the user is selecting people. The ones who can't have access shouldn't be selectable in the first place."

Same words — "control who accesses what" — two completely different features. We built enforcement. They wanted prevention.

And here's the part the customer never sees: the selection component was a vendor SDK. Validating at selection time wasn't something it supported. An architectural constraint, invisible from the outside. The customer, correctly from where they stand, did not care. They don't buy SDKs. They buy features.

What eventually shipped was a custom control born from debate rather than design: pre-selection filtering bolted onto the SDK, post-action checks kept as a safety net. The customer agreed. Nobody was happy. And the most expensive part wasn't the code. It was the weeks of back and forth — half of them spent explaining the requirement not to the customer, but to our own business side.

Business people love the sentence "we can build everything." It's almost correct. MacGyver never builds the thing he wants. He builds the thing the room allows. Paperclip, duct tape, a chewing gum wrapper — the inventory is the constraint, and the trick is working inside it. The correct sentence, the one nobody puts on a slide, is: we can build everything the system allows us.

The Telephone Game

Features are rarely 100% what the customer expected. Not because anyone is incompetent. Because of the path.

Customer explains a need to an account manager. The account manager summarizes it to product. Product turns it into a ticket. A developer reads the ticket. Four hops, and every hop compresses. A request, a spec, a Jira ticket — each one is a lossy compression of intent. And everyone downstream decompresses it with their own codec: the developer fills the silence with the narrowest technically-clean interpretation, QA fills it with the broadest, the customer fills it with the picture that's been in their head since the first phone call.

We pour money into the stages. CI/CD pipelines, test coverage dashboards, deployment automation — the middle of the SDLC is over-tooled. The handoffs get a text field and a prayer.

Which is exactly backwards, because the ticket that arrives is almost never self-contained. And the silence inside it is where the next war starts.

Bug, Missing Functionality, or Enhancement: Pick Your Fighter

The feature ships. QA opens fire.

"The UI is not refined enough." The dev answers: works as designed. "The system doesn't support this file type." Not in the ticket. "It would be nicer for the customer if the flow did this." That's a wish, not a defect.

It looks like a classification debate — bug versus missing functionality versus future enhancement. It isn't. Nobody in that meeting actually cares about taxonomy. It's a budget negotiation in disguise. The real questions being decided are: what gets fixed in this iteration, what gets declared out of scope forever, and what gets exiled to "next iteration" — the place where backlog items go to die.

The label gets written afterwards, as justification for the verdict. Watch closely next time: the classification always, miraculously, matches whatever the sprint could afford.

Shall We Play a Game?

In WarGames, WOPR has simulated thousands of nuclear scenarios. Every strategy, every escalation, every outcome — modeled. And the near-apocalypse walks in through none of them. It comes through Falken's backdoor: a login that exists in the real system but in nobody's model of it.

Our version: a support ticket. "I selected this file type, this recipient, this classification — and it failed."

The investigation finds the cause: the user had a role that made the SDK fail to block him. A role that shouldn't exist on a human — an IT admin service role, not meant for actual users of the system. No QA tenant ever contained that role, because QA tenants are a model of production, and models are always smaller than reality. One combination of file type, recipient, classification, and an impossible role — and the whole flow falls over.

One test user affected. Full escalation anyway. Support ticket, severity high, management on the call.

Because the customer's severity function has exactly two values: works and fails. Probability is our variable, not theirs. They don't see "0.1% of users in an edge configuration." They see a red X, and a red X is not damage — it's evidence. It breaks their trust in everything that didn't fail. What else is broken that we haven't found yet?

The resolution order, learned the hard way, is always the same: first manage. Then argue severity. Then explain. Then fix. The fix is the last step, and by far the easiest one.

KARR

Knight Rider fans remember KARR: the prototype built before KITT. Proof that the technology works — and nothing else. No safety design, no ethics module, self-preservation over mission. Deactivated, stored, never properly decommissioned. And of course it comes back to bite. Twice.

KITT is what you build afterwards, when you take the lessons and design properly.

Every productionized POC is KARR.

The anatomy is always the same. Say you need a system that receives a newsfeed from a provider, processes it, and revokes access accordingly. You grab the provider's SDK. You find the sample code closest to your case. You change the parameters that matter and leave the dead code where it is. You write a script that stands up the infrastructure, run the thing end to end once — it works. Demo day. Applause. Someone from business says the fatal sentence: "Great. Ship it."

What the demo does not contain: logging. Error handling. Metrics. Scaling. And any respect whatsoever for the vendor — throttling, retries, their error cases. The POC treats the provider as a function that always answers. Production introduces you to what the provider actually is: a moody dependency with opinions and rate limits.

Never productionize a POC. Write an MVP instead. An MVP with one functionality beats a POC with three — because a POC proves the system can, an MVP proves the customer wants, and only one of the two was ever designed.

Closing the Distance

So how do you get it right? I don't have a framework. I have observations from the times it hurt less.

Get the customer in the loop early — kick-off to production, not kick-off then silence then surprise. Show mockups and a feature map before writing code; pictures fail much cheaper than deployments. Start with an MVP and let feedback refine it — don't target the full solution in one shot, let reality correct the requirements while correction is still cheap. And when the MVP lands, reserve time for refinements before jumping to the next feature. Iteration two is where the expectation gap actually closes. Skip it, and the gap ships to production permanently.

And building without design and a plan will bite you down the road. It always does. With interest.

Every one of these is the same move wearing different clothes: shorten the distance between intent and feedback.

The Room

The customer will keep asking for the Swiss Army knife. Business will keep promising it. QA will keep discovering the silence in the tickets, and some role that shouldn't exist will keep walking through the backdoor.

Fine. That's the room. MacGyver doesn't complain about the room — he inventories it.

We can build everything. Everything the system allows us.