DEV Community

Cover image for When AI Writes Fast, Verification Is the Real Feature
Chaminade Dondah ADJOLOU
Chaminade Dondah ADJOLOU

Posted on

When AI Writes Fast, Verification Is the Real Feature

AI coding assistants made something weird happen on my desk in Lomé: I can scaffold a Node API, a React dashboard, and a Flutter screen before my coffee cools. The problem is not speed anymore. The problem is that plausible code arrives faster than my brain can distrust it.

I am not anti-AI. I use it daily for fullstack and community work around GDG Lomé. I am anti-shipping vibes. This post is the verification habit I wish I had written down earlier — a practical loop for builders who generate a lot and want to sleep at night.

The new bottleneck is not typing

A few years ago, the bottleneck was "how do I write this Express route?" Today the bottleneck is closer to:

  • Did this handler actually enforce auth on every path?
  • Does this React form recover when the network drops mid-submit?
  • Will this Flutter screen still work on a mid-range Android with spotty 4G?
  • Did the model invent an SDK method that looks real?

Cheap generation moves the cost downstream. Your job becomes product judgment, contract clarity, and tests that catch confident mistakes.

A verification loop that fits a solo or small team

Five-step verification loop: contract, small diff, sharp tests, bad network, human checklist

Figure: the verification loop before you trust AI output.

I use a five-step loop. It is boring on purpose.

1) Freeze the contract before you paste code

Before asking an assistant for implementation, write the contract in plain language (or TypeScript types / OpenAPI stubs):

  • Inputs and outputs
  • Auth rules
  • Failure modes (timeouts, empty lists, partial writes)
  • What must never happen

Example for a meetup RSVP endpoint:

// Contract first — not generated, handwritten
type RsvpRequest = {
  eventId: string;
  userId: string;
  seats: number; // 1..5
};

type RsvpResult =
  | { ok: true; confirmationId: string }
  | { ok: false; reason: "FULL" | "CLOSED" | "UNAUTHORIZED" };
Enter fullscreen mode Exit fullscreen mode

If the assistant cannot implement that shape, reject the patch. Do not negotiate the contract away because the generated code "almost works."

2) Ask for the smallest diff, then re-read like a reviewer

Large pastes hide landmines. Prefer:

  • One file at a time
  • One concern at a time (validation OR persistence OR UI, not all three)

When you review AI output, hunt for these patterns:

  • Happy-path only (no catch, no empty states)
  • Silent defaults (|| [], ?? true) that mask bugs
  • New dependencies you did not ask for
  • Comments that explain intention the code does not actually fulfill

Treat the model like a fast junior teammate: useful, earnest, occasionally inventing APIs.

3) Prove behavior with tests that would embarrass you if they failed in prod

You do not need a cathedral of coverage. You need a few sharp tests:

  • Auth denied when token missing
  • Idempotent create (double submit does not double-charge seats)
  • Timeout path returns a safe error, not a half-written row
  • UI shows offline / retry, not a blank spinner forever

For Node, I keep a thin integration test that hits the real router with a test DB or in-memory stand-in. For React, I test the state machine of the form, not the CSS. For Flutter, I test the repository layer that wraps http / connectivity — that is where "works on my fiber" lies die.

4) Run it on the worst network you can borrow

If you build for people in West Africa (or anywhere with inconsistent connectivity), verify on:

  • Chrome throttling (Slow 3G)
  • A real phone on mobile data
  • Airplane mode toggled mid-action

AI-generated UIs love optimistic updates. Optimistic updates without conflict resolution are how you create ghost RSVPs and duplicate chat messages. Pair optimism with:

  • Client-generated idempotency keys
  • Clear "pending / synced / failed" UI
  • Server rules that win on conflict

5) Keep a "human owns this" checklist for every PR

Even for solo work, pretend you have a reviewer. My checklist:

  • [ ] Auth and authorization checked on every branch
  • [ ] Secrets never logged; env vars documented
  • [ ] Migrations reversible or at least noted
  • [ ] Feature flag or kill switch if the AI feature talks to a paid API
  • [ ] One paragraph in the PR describing what could go wrong

That last line is gold. If you cannot describe the failure mode, you do not understand the patch yet.

What I ask AI to do vs what I keep

Good asks

  • Boilerplate for Zod schemas from a type I already wrote
  • Refactors with a clear before/after
  • Test stubs matching an existing function signature
  • Explanations of an unfamiliar error after I paste the real stack trace

Bad asks (unless you verify hard)

  • "Build the whole auth system"
  • "Make it production ready"
  • "Add AI to the app" with no product boundary
  • Blindly accepting a dependency upgrade "because the model said so"

A concrete Node + React pattern: verify the money path first

Whatever your product, find the money-or-trust path (payments, RSVPs, grades, medical-ish data, admin deletes) and verify that first.

Pseudo-structure I reuse:

POST /api/rsvp
  1. authenticate
  2. validate body (seats 1..5)
  3. transaction:
       - lock event row
       - check capacity
       - insert rsvp with idempotency key
  4. return confirmation or typed failure
Enter fullscreen mode Exit fullscreen mode

Then I ask the assistant to implement only step 3 given the surrounding stubs. After merge, I manually break it: send duplicate keys, expire the session mid-flight, fill the event to capacity. If those cases are ugly, the feature is not done — no matter how pretty the generated UI looked.

Community note (without the spam)

At GDG events, the most useful demos are rarely "look how much the model wrote." They are "look how we caught the bad path." If you mentor beginners, teach verification as a first-class skill alongside prompts. Otherwise we train a generation that can generate apps they cannot operate.

Takeaways

  1. Generation speed moved the bottleneck to verification — budget time for it.
  2. Write the contract first; reject code that drifts from it.
  3. Prefer small diffs and sharp tests over giant pastes.
  4. Validate on bad networks and conflict scenarios, not just localhost.
  5. Keep a human-owned failure-mode note on every change.

AI can draft your feature. You still ship the truth.

If you are building with Node/React/Flutter and AI assistants, what is the one check you refuse to skip? Drop it in the comments — I am collecting a practical list for a future GDG workshop.

Top comments (0)