What happened
I was debugging a CI pipeline. Migrations weren’t running, tests were failing. Somewhere in the Nth commit of a brutally broken CI, the Cursor agent suggested a fix: add db:drop to the Makefile’s db-prepare target.
# Before
db-prepare:
bundle exec rails db:create db:migrate
# After
db-prepare:
@echo "=== Starting db-prepare ==="
bundle exec rails db:drop db:create db:migrate --trace
That’s a destructive command. It deletes the entire database. In a Make target that also runs during deployment. At this point the system was already doomed — but nothing looked wrong yet.
I looked at the diff. Approved.
Then, in a later commit, a second agent saw the db:drop and assumed that’s how we do things in this project. It added a comment and moved on. The change was now normalized — it looked intentional, not like a debug artifact.
Tests passed in the feature branch. CI ran green.
An hour later, on Slack:
“Andrew, did you happen to nuke anything in QA? The entire database, for instance?”
I stared at the message for a few seconds. Then opened the Makefile. Then understood.
db-prepare wasn’t just used for CI tests. The same Make target ran during QA deployments. The first agent didn’t know. I didn’t remember. Human review didn’t catch it. AI review didn’t flag it. Everyone looked at the diff and saw a reasonable change.
By the instruments, everything was fine. In reality — an empty database, zeros across the board.
It kept going
The next morning. A teammate digs into a failing Elasticsearch issue:
“Andrew, did you decide to brutalize db-prepare? It now has
rake elastic:reindex_allin it. CI is crashing on an empty database because of this.”
The agent had kept “fixing” the Makefile. Each agent saw what the previous one left behind and built on it. Nobody reverted to the original.
And then, the next evening:
“Wait — we didn’t actually fix the db:drop. It’s going to wipe the database again on the next QA deploy.”
We almost dropped it twice.
One agent introduced the destructive command. A second agent normalized it. A third agent added more damage on top. Each one operated locally, rationally, correctly — within the three lines of code it could see.
Code must do what it says
Our CI pipeline had a step called db_prepare. It didn’t just run migrations. It also created the database — implicit assumption from the first deploy. A colleague said that’s the convention. I said: two separate steps, db_create and db_migrate. If you don’t know the meta-context, the name lies.
A human can guess that db_prepare might do more than migrate. An LLM trusts the text 100%. If the name says migrate, the agent assumes migrate. If the Makefile target is called db_prepare, the agent treats it as test preparation — not a deployment step.
Every implicit convention in your codebase is a mine for an AI agent. The agent doesn’t have the team’s oral history. It has filenames, function names, and comments. If those lie — even by omission — the agent will build on the lie.
What actually went wrong
The easy answer: I approved a bad diff. Human error.
The real answer: when I wrote code by hand, I had time to think. While typing db:drop, something in my head would flicker: “Where else is this used?” Slowness created space for reflection. Now the agent produces a complete solution in seconds. I shift from writing code to approving code. From author to validator. A validator sees what’s shown to them. They don’t see what’s not in the diff.
AI agents optimize locally. They accelerate the right answer to a narrow question. But the narrow question is almost never the whole problem. The agent solved what it saw. I approved what I saw. Nobody saw the system.
This isn’t a one-time mistake. It’s structural. The faster the agent generates, the less time the human spends understanding. The more agents touch the same file, the more each one builds on the previous one’s assumptions. Errors compound.
Why we didn’t lose the business
The error cost us about 30 minutes. Here’s why:
A QA environment exists. We don’t vibe-code to production. There’s a place where things can break — and it’s not prod.
Automated backups work. The morning RDS snapshot was there. Ilya found it in under a minute.
The team knows how to restore. Terraform state import, instance renaming, migration reruns — routine they’d practiced.
The irony: a month before the incident, we’d discussed dropping the QA environment. “Why do we need separate QA? Feature flags and straight to prod, like every modern team.” We didn’t drop it. Too lazy to migrate. That laziness possibly saved us client data and reputation.
All of these are “boring” practices. Backups, staging, runbooks, disaster recovery. The stuff teams want to get rid of when “we’re on AI now, everything’s faster.”
SDLC standards exist for a reason
CI/CD, test environments, code review, disaster recovery — all of this was formulated over decades. Not because “that’s how it’s done.” Because people lost data, money, clients, companies.
AI agents don’t make these practices obsolete. They make them more important.
Before, you could push 5 changes a day and miss one mistake in five. Now you push 50 changes a day — and miss one in fifty. One mistake per day instead of one per week is a radically different risk profile.
Can you add vibe coding to existing processes? Yes. We do. Can you build everything on vibe coding without processes? No. Vibe coding is a turbocharger. A turbocharger on a car without brakes isn’t speed. It’s a crash with acceleration.
Before you trust the agents…
For a structured way to manage agents in delivery, see Karo’s AI agent management framework.
Checklist:
At least one non-production environment for testing
Automated backups, verified by actual restores (when did you last run one?)
CI fails loudly on critical changes — migrations, DB schema, deploy configs
Code review includes “what else does this affect?”
Make targets and CI steps do what their names say — nothing more
Implicit conventions are documented or eliminated
Destructive commands have environment guards
That evening I wrote to the team:
“Sorry guys, I vibe-coded too hard.”
The responses:
“Real ones don’t apologize.”
“No worries, we’ll drill the restore. We don’t practice those often enough.”
That’s healthy engineering culture. Not “we don’t have errors” — but “we have a system that survives errors.”
AI won’t break your system. It will expose what was already fragile.
P.S. If this sounds obvious — good. You’re one of those who won’t lose prod. But I’ve seen enough teams that decided CI/CD is legacy and staging is a waste of money. This is for them.


