Skip to content

From Software Engineering to AI-Native Engineering

TL;DR: Generating code got cheap. Deciding whether it is correct did not. The teams struggling with AI-assisted delivery are mostly teams that had thin review discipline before and have now industrialized the output side of a process whose input side never scaled. I know this because I pointed an agent at my own portfolio — a site I had shipped and considered finished — and it found two critical defects I had been serving to visitors for two years.

The velocity trap

The first thing that happens when a team adopts AI assistance seriously is that output goes up and throughput does not.

More diffs arrive. They arrive faster. They are, on average, syntactically fine. And then they queue, because the number of people who can say "yes, this is the right change" has not moved at all. The bottleneck did not disappear. It relocated, from the keyboard to the review queue, and it is now somewhere with far less slack.

This is not an argument against AI assistance. I use it daily and I am not going back. It is an argument about where the difficulty went, because a lot of teams are still optimizing the part that stopped being hard.

What actually moved

Roughly, engineering effort used to distribute like this: understand the problem, decide the approach, write the code, verify it, maintain it. Writing was a meaningful slice.

It is now a small one. What did not shrink:

  • Deciding what to build
  • Deciding whether what got built is right
  • Knowing which existing behavior is load-bearing
  • Carrying that context forward six months

Every one of those is a judgment problem, and judgment is exactly what does not come out of a model. Worse, the AI-assisted workflow actively erodes one of them: an agent starts each session with no memory of why the last session made the choices it did.

Specification stops being ceremony

I had always treated heavyweight specification as something that happened on projects with too many stakeholders. Working with agents changed my mind, for an unromantic reason: a specification is the only artifact that lets you review intent rather than text.

When a human writes a 400-line diff, you can usually infer the intent from the code, because a human's mistakes are correlated. They misunderstand one thing and it shows up in a consistent way. An agent's mistakes are not correlated like that. It can produce a diff that is locally reasonable everywhere and wrong as a whole, and reading it line by line will not surface that.

So the review has to happen earlier, against a statement of what the change is supposed to do. That is all a spec is here. Not ceremony — a reviewable statement of intent, written before there is a diff to be seduced by.

The git history of the site you are reading this on shows the shape of it. Three commits, consecutive: "language switcher improvements", "v2", "v3". None of them explains what was wrong. None explains whether it was fixed. It was not — the same feature was still broken two years later, and I only found out because something re-examined it from scratch.

The worked example

I pointed an agent at this site with an unglamorous instruction: audit it, against the live deployment, and tell me what is wrong.

I expected a tidy list of dependency upgrades. What came back was worse, and more useful.

Every page declared the homepage as its canonical URL. A single line in the root layout — canonical: '/' — inherited by every nested page. I had been telling search engines that /about, /skills and every Spanish page were duplicates of the homepage. For two years. The site rendered perfectly; the defect was only visible in the response headers, which is exactly the kind of place a human stops looking once the page looks right.

The English homepage was throwing away its server HTML on every load. Two client components compared usePathname() against a literal '/'. Under the default-locale rewrite the server evaluates that pathname as /en and the browser evaluates it as /. Different values, different rendered trees, hydration mismatch — and React responds by discarding the server HTML and re-rendering the entire root on the client. Every benefit of static generation, gone, on the most visited page. Five React errors in the console that I had never opened, because why would you open the console on a page that looks fine.

Then the ones that are just embarrassing. Two AWS certification badges swapped, so the Solutions Architect entry displayed the Developer badge — on the one page whose whole audience recognizes those badges on sight. Prose links at 2.38:1 contrast against a 4.5:1 requirement, failing WCAG for every link on the site. An employment record that had my career starting four years before it actually did.

Twenty-nine findings. Two critical.

What the agent got wrong

This is the part that matters, and it is the part these articles usually skip.

It measured badly and reported confidently. The first contrast scan it wrote returned failures that were not real. It walked up the DOM for the first non-transparent background and used that — without compositing the alpha — so any translucent surface produced a wrong number. It also read textContent, which picks up descendant text and attributes it to the ancestor's color. Both produced phantom 1:1 failures. If I had accepted the output, I would have "fixed" things that were correct.

It got the direction of a finding backwards. It flagged a contradiction between my bio and my structured data — the bio said I ran a SWAT team, the data said Principal Technical Lead — and concluded the bio was stale. The bio was right. The structured data was four years out of date. It picked the wrong one because both were plausible and it had no way to know which reflected reality.

Its own safety net had a hole in it. It wrote a locale parity checker to guarantee Spanish never drifts from English, using indexOf('es: [') to find the Spanish block — which matches technologies: [. The check was reading the Spanish array as empty and would have passed a file with zero Spanish entries. The tool whose entire job was preventing a class of bug contained that bug.

None of these are arguments against the approach. They are arguments about where the human has to stand. Every one was caught by verification — measuring instead of asserting, checking a claim against reality, testing the checker against a deliberate failure. That is a discipline, and it is not optional.

Trade-offs

This is overhead on small work. For a one-file fix, writing a specification first is pure ceremony and I would not do it. The threshold, roughly: if you would want to argue about the approach before seeing the diff, write the intent down. Otherwise do not.

Verification is slower than it looks. "Run the build" is not verification. Checking whether the homepage still hydrates means opening a real browser and reading the console. Checking contrast means computing ratios, and then checking the thing computing them. Budget for it, because the alternative is trusting output, and trusting output is how you get a confident wrong answer.

Specs rot. A specification that no longer matches the system is worse than none, because people believe it. If you are not going to update them when the change lands, do not write them.

What I would actually do

If you are adopting this on a team:

  1. Move review earlier. Review intent before implementation. It is cheaper there and it is where an agent's uncorrelated mistakes are visible.
  2. Write decisions down. Not process documents — decisions, with the reasoning. An agent starts every session with no memory; so, in practice, do people at six months.
  3. Make verification concrete. "It builds" is not a gate. Name what you will measure and how you will know.
  4. Verify the verifier. Test your checks against a deliberate failure. If a check has never failed, you do not know that it can.
  5. Keep the human on judgment. Not on typing. The model is better at typing than you are, and worse at knowing which of two plausible things is true.

The uncomfortable part of all this is that none of it is new. Specification, review discipline, honest verification, writing decisions down — this is unfashionable engineering practice that a lot of teams quietly stopped doing because they could get away with it.

AI removed the getting-away-with-it.


Everything in this article is verifiable. The audit, the specifications, the findings and the fixes are all in the repository this site is built from, including the ones that make me look bad.