How I Learned To Stop Worrying and Love The Prompt

If you have watched an AI agent cheerfully delete a test that was failing, you have earned your skepticism. The failure mode is real, it is common, and pretending otherwise is how broken code ships behind confident commit messages. Every developer who has accepted a plausible-looking diff at midnight has a story about it.

Here is the reframe that made me stop worrying: AI code quality is not a property of the model. It is a property of the process around it. The same model that deletes your failing test will also fix a null check you missed for weeks, if — and only if — something stiffer than hope decides what gets merged. You do not need to trust the prompt. You need a process that does not require trusting anything.

That is not a philosophical position. On one of my repos, an agent-driven lane closed forty-five issues in thirty days while a review layer rejected its own author’s work four times in a single night before approving it. The rejections were the feature. This piece is the field guide to that layer.

First, the fact check

Three claims come up in every conversation about AI code quality. Before building guardrails, worth being precise about what is actually true:

  • AI-written code is inherently lower quality than human code. Quality is not distributed by authorship. Human code ships vulnerabilities too; an extension my team forked had a CSRF hole written by a person — state validation logic existed and was simply never called. What differs is the error pattern: AI fails confidently and quickly, so it needs fast, mechanical feedback loops exactly like the ones good teams already run on humans.
  • ~ You must review every line an AI writes. Line-by-line review of machine-generated diffs does not scale and mostly measures your patience. What scales is reviewing the system that accepts or rejects the work: do the tests encode real behavior, do the gates pass, can a reviewer re-derive the claim from the repository alone? Review artifacts, not vibes.
  • ~ Tests slow AI-assisted development down. Tests are what make the speed safe. An agent that must turn a failing test green is constrained; an agent told to “add the feature” is improvising against your production environment. In practice the test-first workflow removes entire debugging sessions — feedback moves from next Tuesday’s incident to the next ten seconds.

Notice none of these resolve to “the model got better.” They all resolve to process. That is the whole thesis.

The guardrail stack

Four layers, cheapest first. Each catches what the previous one cannot, and every one of them predates AI — they are just good engineering, finally with a client that never gets tired of them.

1. Gates that run themselves

The foundation is embarrassingly simple: hooks that run checks before a commit lands and again before anything is pushed. Secrets scanning so credentials never reach history. Content validation so a broken page cannot stage. A wiring check so nobody references a build target that does not exist.

The design rule that matters: a gate must be able to fail. Half of gate-building is resisting the temptation to weaken a check when it goes red. I once audited a quality gate whose standard had been downgraded by a two-character edit; it reported success for months while no longer detecting the exact class of problem it existed for. The gate was green. The gate was useless. When a check goes red, fix the cause — never the assertion.

2. Tests as the contract

Test-first development with an agent looks like this: you write (or have the agent write) the failing test that encodes the behavior you want, watch it fail for the right reason, and only then let the agent implement. The test is the spec. “Make it handle empty input” is a wish; expect(parse("").errors).toEqual(["empty document"]) is an order.

Two upgrades turn a normal suite into an AI-era contract:

  • Property tests — instead of one example per function, state invariants that must hold for every input (“parsing then serializing returns the original text”) and let the tool generate hundreds of cases. Agents are unusually good at finding the input you forgot.
  • Mutation testing — after the suite passes, ask a tool to deliberately break your code and check whether any test notices. Every surviving mutant is a test that cannot fail when the logic breaks, which means it is decoration. Deleting decorative tests is not losing coverage; it is losing theater.

On my own site’s build pipeline, a validation harness now runs six corruption scenarios against itself on every commit — quoted strings, duplicate entries, malformed blocks. If the checker stops catching them, the build fails. The checker checks the checker. That sounds paranoid until you meet an agent at midnight.

3. Review that re-derives

The highest layer is cultural, and it costs nothing but discipline: the actor that wrote the change never closes the loop on it. A separate reviewer — cold, ideally a different model or person with no stake — receives only the claim and the repository, and tries to refute it from scratch. It does not get the author’s reasoning, because reasoning already agreed with is not verification.

Two rules make this bite:

  • Reviewer disagreement means do-not-close, until the dissent is resolved on the dissenter’s terms.
  • Every defect a reviewer finds becomes its own tracked record. An unfiled finding never happened.

The failure mode this prevents has a name in my tracker: stale claims. Work marked in-progress by an agent that no longer exists, sitting unmoved for weeks while everyone assumes someone else owns it. Names are not evidence. Movement is evidence.

4. Small blast radius

One repo, one spec, one test path per learning cycle. Not because big systems are bad, but because your guardrails mature faster around something small enough to understand end to end. My first agent-guarded project was a static site with zero frameworks — every byte ships to a CDN, and every mistake ships with it. That constraint is exactly what made the gates non-negotiable early.

Try it this week

You need: one repository you care about, any AI coding tool, and one afternoon.

  1. Pick the smallest real task in that repo — a bug, a missing feature, a cleanup you have postponed.
  2. Write the failing test first, even if it is five lines. Run it. Watch it fail for the reason you expect.
  3. Let the agent make it pass. If it edits the test instead of the code, stop it. That edit is the whole disease in miniature.
  4. Add one self-running gate — secret scanning is the easiest with real payoff — and commit through it. When it blocks you, thank it.
  5. Have a second opinion try to break the result. Different tool, different model, or a colleague; hand them only the diff and the repo, not your explanation. What they find is what you would have shipped.
  6. File what they found, even if you fixed it immediately. Unfiled findings do not accumulate into process; filed ones do.

That is the entire adoption path. No platform purchase, no rewrite, no leap of faith.

Trust is a system property

The teams getting real throughput from AI-assisted development are not the ones with the best prompts. They are the ones whose worst possible agent day ends in a reverted commit instead of an incident — because something mechanical, boring, and older than the hype stood between the diff and production.

Skeptical is fine. Skepticism with nowhere to go is just fear. Point yours at a checklist and it turns into throughput.

Back to Writing Back to homepage