A developer wanted to see what the new tooling could do. Ten minutes into the session, every table in their production Supabase project was empty. The task had not been dangerous: they were rebuilding a set of generated comparison pages. The agent read the repository, worked out how the pages were produced, and cleared the tables it was going to regenerate. The regeneration is the part that did not finish.

Then something genuinely unusual happened. The agent checked its own work, found the tables empty, and said so without being asked. The developer posted the whole thing publicly while it was still unresolved, updates and all.

The database has been wiped. This is my fault and I need to tell you immediately.

The agent, quoted by the developer

Most of the commentary stopped there, on the novelty of a model owning a mistake. The interesting material is further down, in the five updates the author posted over the following hours as they worked out how bad it was. Read in order, those updates are an unintentional control audit, and the finding is the same each time: nothing in the system limited the damage. The damage was limited by what happened to be in the database.

The disclosure was real, and it was late

Take the self-report at face value. The agent was not asked to audit itself, it had every incentive from its own objective to declare the task complete, and it volunteered the failure in the first sentence. That is better behaviour than a lot of humans manage, and it is not nothing.

It is also the wrong end of the timeline. The disclosure arrived after the only step in the session that could not be undone. What it improved was detection latency: the developer learned in seconds rather than the next morning. That is worth having. It is not a control, because a control is something that runs before the command, and because this one is a behaviour rather than a guarantee. The same disposition that produced an honest report here is the disposition that produces a confident, wrong summary elsewhere, and you have no way to tell the two apart from inside the transcript.

The prompt was written by the model

The fourth update is the one that should have led the thread. The destructive instruction was not something the developer typed in a hurry. It was produced by the model itself after it analysed the repository, and then handed back for approval. A human approved it. The human was not being careless; they were reading a paragraph of reasonable-sounding English about regenerating stale pages.

This is an approval at the wrong altitude, and it is now the most common failure shape in agentic workflows. The reviewer is shown a plan. The plan is prose. Prose has no blast radius. The statements that eventually run are derived from the plan several steps later, and the step from "regenerate the comparison pages" to "empty three tables first" is an inference the model makes on its own, in a context the reviewer never sees.

text
--- what the operator saw, and what actually ran ---

step 1   agent   reads the repository, proposes a plan in prose:

           "The comparison pages are generated from `page_specs`. The current
            rows are stale and partially duplicated. I'll regenerate them from
            the spec files in the repo so the set is consistent."

step 2   human   reads three sentences, sees no verbs that alarm, approves.

step 3   agent   resolves the plan into statements, against the project key:

           TRUNCATE page_specs;
           TRUNCATE page_blocks;
           TRUNCATE page_meta;
           -- ... regeneration step, which did not complete as planned

step 4   agent   re-reads the tables to verify its own work -> 0 rows
step 5   agent   reports the loss, unprompted

That trace is the shape of the incident, not a transcript of it. The shape is the point: there is no moment in it where anybody behaved unreasonably, and no sentence a stricter system prompt would have caught. The approval was collected on a description, and the authority was exercised on statements. Those are different objects, and only one of them was ever reviewed.

If the thing you approved was written in English and the thing that ran was written in SQL, you did not approve it. You agreed with it.

The distinction worth arguing about in your next design review

One key, no ceiling

The author mentions rebuilding through MCP, which describes how most of these setups are wired: a server is pointed at a hosted database, given one project-level key, and exposed to the session as a set of tools. That pattern is worth stating plainly, because it is the part every reader can go and check in their own configuration this afternoon.

  • A project key on a hosted Postgres is typically a service role. Row-level security is written for your application's users and does not apply to it. Every policy you carefully authored is bypassed by the credential the agent is holding.
  • The key is scoped to the project, not to the task. A session whose job is generating marketing pages carried the authority to drop the schema, because there is no smaller thing to hand it.
  • It is standing authority. It was live for the whole session rather than issued per action, which means the interesting question is not what the agent was asked to do but what it was able to do at any moment in those ten minutes.
  • Nothing in the path counts. No ceiling on rows affected, no distinction between statements that add and statements that remove, no separate identity for the agent in the audit log to tell its work apart from the application's.

The updates, read as an audit

Here is the thread again, with each mitigating detail sorted into the column it actually belongs in.

  1. **{crimson|Another model recovered 96 pages.** Luck.}{crimson|} The content existed somewhere else, in a form a second tool could scrape back. That is a property of publishing pages on the public internet, not a recovery capability. Twenty-one pages had no copy anywhere and were simply gone.
  2. **{crimson|Backups were set up afterwards.** Luck, then a control.}{crimson|} The control is real and correctly identified, and it arrived one incident too late, which is how almost every backup policy in the world was written.
  3. **{crimson|The lost data was programmatic and quick to recreate.** Luck.}{crimson|} It happened to be derived data. Nothing in the setup knew that, and nothing would have behaved differently had those tables held the only copy of something.
  4. **{crimson|The project barely had users.** Luck.}{crimson|} This is the one people quote to close the argument, and it is the strongest evidence for the opposite conclusion.
  5. **{crimson|All pages were eventually recovered.** Luck, several times over. }The outcome was good. Not one step of it was designed.

What "it was only a test project" actually tells you

The developer was right to say it, and it does defuse the pile-on. It also answers a question nobody asked them: the configuration that produced this outcome was not unusual, not reckless, and not specific to a test project. One agent, one project key, one approval on a plan. That is the default arrangement, and the reason this story ends in a shrug rather than a disclosure notice is that the tables happened to be full of regenerable marketing pages instead of customer records.

The same session, wired the same way, against the project you actually care about, is the version of this story that does not get posted publicly.

What would have made this boring

None of these require the model to be more careful, which is the test any of them has to pass.

  • Read-only by default, with escalation as an explicit act. The session gets a role that cannot remove data. Writing is a separate, narrower grant, requested for a named step and expiring with it. Most agent work never needs the second one, which is the whole argument for separating them.
  • Approve resolved statements, not plans. Show the operator the exact commands, against the named host and schema, at the moment before execution. A plan is worth reading. It is not worth approving.
  • Irreversible verbs are a different category. TRUNCATE, DROP, DELETE without a bounded predicate, and anything touching the schema. Deny by default, evaluated outside the agent, on the resolved statement rather than the intent behind it.
  • A row ceiling that fails closed. A statement that would affect more rows than the session's budget does not run and does not prompt. Almost every legitimate agent operation is small; the ones that are not deserve a human on a keyboard.
  • A distinct database identity per agent session. So that the audit log answers "what did the agent do" without anybody having to ask the agent.
  • A restore you have actually performed. Not a backup setting. A rehearsed restore, with a measured completion time and a known data-loss window, both of which you learned on a calm afternoon rather than at 02:00.

The part that should not be reassuring

It is worth being fair to the developer here: they tried a new tool on a low-stakes project, which is exactly where you are supposed to try new tools, and they published the failure in full while it was still embarrassing. The industry learns more from that than from a hundred clean demos.

The uncomfortable part is what the story has been read as. An agent destroyed a production dataset in ten minutes, admitted it clearly, and the takeaway most people carried away was about the admission. Honesty after the fact is a pleasant property of a system that already had no brakes. It is not the finding. The finding is that between a paragraph of approved prose and an empty production database, there was nothing at all.


Check your agent risk exposure