<- all posts

Six Questions Before Any Code Got Written

// 2026-08-19 · Frederic Haddad · 8 min read

ai-agentsengineeringautomation

The request was simple: build this one the way we built the last one. Same pattern, same discipline, ship it.

What I got back was six questions.

This was for one of my own operations — a new feature hanging off a date. A step that runs through a third-party system, then a confirmation back to the customer. Everyone involved, me included, assumed it was most of the way there already. There was a screen. There was a status field. The job looked like wiring up plumbing that had already been installed.

It wasn't. And the only reason I found that out before building on top of it is that nothing got written for the first stretch of the session.

Two agents read the code before anyone asked a question

Before the first design question, the session did something I now insist on: it sent two sub-agents into the codebase in parallel, purely to find out what was actually there.

One mapped the current implementation of the feature. The other mapped the reusable surface of the recent, well-received feature I'd asked it to copy — what that engine actually did, what was genuinely reusable, what was welded to its own use case.

Neither agent was allowed to propose anything. Their job was to come back with a map of the building as it stands, not as anyone remembers it.

This is the part most teams skip, including mine when I'm in a hurry. Design conversations normally run on memory — someone's recollection of what the system does, filtered through what they wish it did. That's how you get a design that's internally beautiful and factually wrong about the code it has to land in. It's the read-only scouting phase I now put at the front of any serious build, including the full legacy migration that started with ten agents reading before a single line was written.

It's the difference between quoting a bathroom renovation from the doorway and opening the wall first. Same job, two completely different quotes.

What the map found

Three things came back, and all three changed the design.

There was no dedicated data model at all. The feature everyone thought was "basically working" had nowhere of its own to store anything. State was being inferred from a general-purpose status field. That's not a feature waiting for a UI. That's a UI waiting for a feature.

There was a notification event that had never been wired to anything. It existed in the code, correctly defined, and nothing in the system ever triggered it. If we'd built on the assumption that notifications fired, we'd have shipped a silent feature and found out from a customer.

And there was a security gap. A sensitive field stored in plaintext, shown unmasked in an internal view, with no per-account check on file downloads. Internal surface, caught internally, and split off into its own tracked work before anything new got built over it. But it had been sitting there quietly, and no design conversation running on memory would ever have surfaced it.

That third finding is the whole argument for the discovery pass. One of the six design questions only existed because two agents spent a few minutes reading code first. Without them, we'd have built directly on top of it — new feature, new endpoints, more traffic through the same gap.

Six questions, one at a time, each one locked

Then the actual design. Six sections, asked one at a time, each answer locked before the next question was allowed to open.

That sequencing sounds fussy. It isn't. It's the difference between a decision and a conversation. When you get six questions at once you answer the easy ones and hand-wave the rest; when you get one, you have to actually decide.

Here's what got decided:

  1. Reuse the existing engine, or copy and adapt it? Copy. The tempting move was to generalize the recent feature's engine into something shared, and I said no — defer that refactor until a third similar case actually exists. Two instances is not a pattern. It's a coincidence with ambitions.

  2. When do we ask the customer for information? Not on day one. A status indicator that says "action required" for weeks before anything is genuinely required trains people to ignore it. The indicator stays silent until a real dependency completes.

  3. Do two customer notifications collapse into one? Yes. The confirmation and the file upload that goes with it happen in the same sitting in practice, so they became one atomic action and one email instead of two of each.

  4. Fix the security gap now, or later? Later — but tracked, with its own project and its own issues, not folded into this feature's scope where it would quietly delay a date I couldn't move. Splitting it was a deliberate choice. Letting it ride would have been a default.

The last two were procedural: how the rollout runs, and what has to exist in the tracker before implementation starts.

The point of writing all six down is that the trail is auditable afterward. Six months from now, when someone asks why this feature has its own module instead of using the shared engine, the answer is a sentence in a document with a date on it, not a shrug.

Nothing gets built that isn't a ticket first

The last rule was the one that made the rest stick: every build task had to exist in the tracker, linked and dependency-ordered, before a single line of implementation code was written.

Eight milestones. Sixteen implementation sub-issues. Three follow-ups. All filed before the build started.

Planning and building were fully separated — not as a process ritual, but because it's the only way to see the shape of a feature before you're committed to it. Sixteen tickets for something described that morning as "wire up the existing form" is itself the finding. You can look at a list like that and say "this is bigger than I thought" in a way you never can while you're halfway into the code.

Then it built the whole thing in one run

With the design locked and the tickets filed, I gave one go-ahead and stopped supervising.

One continuous autonomous run produced: a new database model, the backend logic module, a customer-facing status page, the events that trigger internal analytics and the customer email and SMS journeys, and an admin action that performs the completion steps as a single atomic transaction — so it either all happens or none of it does.

The lifecycle communications were built twice, on purpose. One version for staging with every delay compressed to a minute, so the whole multi-week journey can be tested before lunch. One for production with the real multi-day delays. Same pattern I use on every flow now, because a communication sequence you can't test end to end is a sequence you're shipping on faith.

647 test suites and 10,057 individual tests passing. One pull request.

The entire thing — brainstorm, tracker setup, full build — fit inside one working session. Roughly two hours, and I didn't read a line of implementation code before the PR existed.

And none of it was switched on

This is the part I'd underline for anyone nervous about autonomous builds.

Every customer-facing communication flow shipped to production inactive. Fully built, fully tested on staging, waiting on a deliberate human decision to go live. The rollout itself runs as a dry-run report first, with an explicit approval and a volume limit before any real customer receives an automated email as a result of the backfill. And the old manual fallback path stayed in place alongside the new one-click action — with a visible warning when someone completes the task the old way, so the fallback stays available without quietly becoming the default again.

I've written before about keeping a human approval gate on anything an agent sends outward; this is the same rule applied to a build instead of a credential. Speed on the code, a gate on anything that touches a customer. Those aren't in tension. The gate is what makes the speed acceptable — and the mechanical stop-gate version of the same idea, for agents operating live systems, is Never Click Pay.

The lesson

The fear I hear most often about AI-assisted engineering is that it will cheerfully build whatever it's told, at speed, including the wrong thing. That fear is correct, and the fix is not a slower model. It's a mandatory design gate: agents read the current system first, questions get asked one at a time and locked, decisions get written to a shared tracker, and only then does anything get built.

The throughput is real — plan to review-ready pull request in an afternoon. But the throughput is only safe because the two hours in front of it were spent finding out that a "small" feature was hiding a missing data model, a dead notification, and a security gap.

A feature that looks like one status button can hide a full stack of missing infrastructure. You pay for that discovery either way: two hours up front, or three redo cycles later.

For companies in Dubai and across the UAE moving from AI pilots into production systems, this is the governance layer that's usually missing — whether the thing being automated sits in customer support, finance operations, HR, or procurement, what's absent isn't a policy document but an enforced sequence that leaves a decision trail your auditors, your board, and your next engineer can all read.

I asked for a feature and got six questions, and the six questions were the most valuable deliverable of the day. If you want to see what a design gate like this looks like on your own codebase — where your assumptions are wrong and what your team is about to build over — that's a consulting day. Book a consulting day or send me an inquiry first if you'd rather talk before booking.