Book a call
  1. Blog
  2. Vibe Coding Rescue
  3. The AI wrote it, so who is going…

The AI wrote it, so who is going to maintain it

AI made writing code cheap, but owning it is still expensive. The one rule, the review checks, and the team habits I use so every AI-written line has a human who can explain it.

A cream code card with an orange sparkle, an ai-generated chip and a dark owner: assigned chip on a soft sand background

A few months ago I was helping a team track down a bug in a billing job. The code was clean, with tidy names and even a test or two. I asked the obvious question: who wrote this part? There was a short pause, and then someone said, “I think Claude did? Or maybe it was Cursor. I just merged it.” Nobody in the room could explain why the retry loop worked the way it did. We had to read it like strangers.

Writing code has become cheap. Maintaining code has not. Every line you merge still has to be read, understood, debugged at 2 a.m., upgraded, and eventually deleted. The AI does not get paged. You do.

Writing got cheap, owning did not

When a person writes a function, ownership comes for free. They know why it exists, what they tried first, and which edge case made them add that weird if. That knowledge lives in their head, and you can walk over and ask them.

When an AI writes the function, that knowledge never existed in anyone’s head. The person who pasted the prompt knows what they asked for. They may not know what they got. So the team ends up with code that has an author on paper and no owner in practice.

I don’t think the answer is “stop using AI”. I use it every day and I’m not giving it up. The answer is to be deliberate about ownership, the same way you would be with code from a contractor you will never see again.

The one rule I start with

If I could only give a team one rule, it would be this: someone on the team must be able to explain every line before it merges.

Not “the tests pass”. Not “it looks right”. Someone, by name, can sit with a reviewer and say what each block does and why it is there. If they can’t, the PR is not ready, no matter who or what wrote it.

This sounds strict, but it changes behaviour in a good way. People ask the AI for smaller pieces, delete the clever parts they don’t understand, and push back on the 200 line answer to a 20 line problem.

And the person who explains it becomes the owner. Their name goes on it. When it breaks, they are the first call.

Review rules for AI output

Normal code review still applies. On top of that, these are the checks I look for specifically when a PR has a lot of generated code in it:

  • Tests are required, and they have to test behaviour. AI is very good at writing tests that only check the mock it just wrote. I want at least one test that would fail if the logic were wrong.
  • No unexplained dependencies. If a new package shows up in the lockfile, someone explains why we need it and why what we already have was not enough. Generated code loves pulling in a library for one helper function.
  • No silent type suppression. Every any, @ts-ignore, # type: ignore or eslint-disable needs a comment saying why. These are often how a model makes an error go away instead of fixing it.
  • No swallowed errors. An empty catch block, or one that just logs and carries on, gets a second look every time.
  • No invented APIs. Check that every function and config option it calls actually exists in the version you run. Models are confident about methods that were renamed two releases ago.
  • The diff matches the ask. If I asked for a bug fix and the PR also reformatted three files and “improved” a helper, I send it back and ask for the fix alone.

None of these are new ideas. What changes is that you can no longer assume the author already checked them, because the author may not have looked that closely.

Put the prompt and the decisions in the PR

Here is a habit that has paid off more than I expected. When a chunk of a PR came from an AI, the description says so, and it includes the short version of the conversation that produced it.

Not the whole chat log. Just enough that a person reading this in six months understands where the code came from. Something like:

## What changed
Retry logic for the invoice sync job.

## How it was written
Asked Claude for exponential backoff with a max of 5 tries.
Rejected its first version (it retried on 4xx errors too).
Kept the second version, rewrote the jitter part by hand.

## Things I decided
- Only retry on network errors and 5xx
- Give up after 5 tries and alert, never retry forever

## Owner
Sunil

That last section is the important one. The decisions are the part that disappears first. The code shows what it does, but only the description shows what you rejected and why. When someone later wants to “simplify” the retry rule back to retrying on every error, the reason not to is sitting right there in the history.

When to accept fast and when to slow down

Not all code deserves the same amount of care. I’m happy to accept AI output quickly for a lot of things: a one-off migration script you will run once and throw away, test fixtures, internal admin pages, CSS tweaks, boilerplate for a new CRUD endpoint that follows a pattern you already have.

Then there is the other list. For these I slow right down, read every line myself, and usually ask a second person too:

  • Authentication and sessions. Login, password reset, token handling, anything that decides who you are.
  • Authorization. Any check that decides what you are allowed to see or change. One missing condition here is a data leak.
  • Payments and money. Webhooks, refunds, currency math, anything that charges a card.
  • Data deletion. Bulk updates, deletes, retention jobs, and migrations that touch production rows.
  • Secrets and infrastructure. IAM policies, security groups, anything that opens a port to the internet.

The pattern is simple. Speed is fine where mistakes are cheap and reversible. Where a mistake costs money, leaks data or can’t be undone, a human goes slow, whoever typed it first. I wrote about a lot of these same weak spots in the first ten things I check when someone hands me a vibe-coded app, and they show up again and again.

A small set of team rules you can copy

If you want something to paste into your team’s contributing guide, this is roughly what I’d start with:

  • Every merged line has a human owner who can explain it.
  • PRs say which parts were AI generated and what was decided.
  • Generated code needs real tests, not tests of its own mocks.
  • New dependencies and type suppressions are explained or removed.
  • Auth, permissions, payments, deletion and infra changes get a slow human review, always.
  • If nobody understands it, it doesn’t merge. Ask for a smaller version instead.

The habit matters more than the tool

Some teams will enforce this with PR templates, some with a CODEOWNERS file, some with a lint rule that flags new @ts-ignore lines. Some will just agree on it in a meeting and hold each other to it. Use whatever you like, the habit matters more than the tool.

AI is a great way to write the first draft. It is not a way to skip owning the result. If your team already has a codebase full of code nobody quite understands, that is fixable too. It’s a big part of the vibe coding rescue work we do at Broadifi, and you can always reach us at contact@broadifitech.com.

But the cheapest fix is the one you make before merge: put a name on it.

Sunil Kr. Samanta

Co-Founder & CTO at Broadifi Tech. Weaving together technology and inner exploration. Built and scaled startups while diving deep into consciousness studies. Equally at home discussing system design or Swami Vivekananda. Currently focused on creating tech that elevates humanity.

Everything by Sunil Kr. Samanta

Start the thread

Your email address will not be published. Required fields are marked *