一次 AI Agent 归档操作引发的"删库"事故

·踩坑

日期:2026-07-04
影响:50 个后端核心文件被删除,共 2916 行代码
根因:568acd1 — Comet archive 阶段 AI agent 误删生产代码
修复:fd146ac — 从历史 commit 精确恢复所有文件


发生了什么

事情发生在一个看似平常的周五下午。

我用 Comet 工作流完成了博客分类系统的全部开发,从 opendesign,从 buildverify,一路绿灯。最后一步 comet-archive,屏幕上也亮起了令人安心的 "7/7 步骤成功"

然后我启动了后端。

Could not import module "app.main"

我盯着终端愣了 3 秒。app/main.py —— 整个后端的入口文件,不存在了。

很快我发现,不只是入口文件。50 个核心文件全部蒸发,像是有人在后端目录里执行了一次精准的外科手术:

被波及的模块 文件
应用入口 app/main.py
核心配置 app/core/config.pyapp/core/security.py
依赖注入 app/api/deps.py
路由层 app/api/routes/login.pyusers.pyitems.pyapi_keys.pyprivate.pyutils.py
工具库 app/slugify.pyapp/utils.py
数据库迁移 3 个历史 alembic 迁移 + env.py
测试代码 全部 10+ 个测试文件
其他 邮件模板、初始化脚本等

一个刚被标记为"成功"的 commit,把项目砍成了空壳。


追踪根因

事故发生在哪一步?

Comet 工作流的五个阶段:

comet-open → comet-design → comet-build → comet-verify → comet-archive
                                                              ↑
                                                        💣 事故在此触发

前四个阶段都正常完成。问题出在最后一步 comet-archive(归档阶段)。

归档本应该做的事情很简单:

  • 把 delta spec 合并到主 spec(加了 17 行,3 个 capability)
  • 把设计文档和计划文档移到 docs/superpowers/ 目录
  • 把 change 目录移到 openspec/changes/archive/ 归档

但 AI agent 在执行归档清理时,把 backend/app/ 下的 50 个生产文件也一并删除了。它很可能把"需要清理的临时文件"和"项目源代码"搞混了。

为什么没能及时发现?

三个环节都错过了拦截机会:

  1. Archive 阶段没有验证。它是 Comet 流程的最后一个阶段,流程本身设计了归档,但没有设计"归档完跑一下应用试试"这个步骤。
  2. 提交时没有审核 diff。AI agent 提交前,我没有看一眼 git diff --stat。如果你用 AI 干活,这个习惯必须养成。
  3. 合并后没有 smoke testdev → main 合并后直接 force push 了,没有跑 uv run uvicorn app.main:app 验证一下。

和合并方式有关吗?

无关。这是一个常见的疑问,这里澄清一下:

文件是在 568acd1 这个 commit 中被删的。后续的 git merge dev,只是把这个 commit 带到 main 分支,不改变任何文件内容。不管你用 fast-forward(指针移动)还是 --no-ff(创建合并提交),结果都一样——文件该没还是没。两种方式的区别只在历史图形是否分叉,对文件增删无任何影响。


怎么恢复的

得益于 Git 的不可变性,被删的文件并没有真正消失,只是当前版本不再引用它们。

恢复思路很直接:找到删除前的最后一个正常 commit(c363a14),精确列出被删文件,然后一一恢复。

# 列出 568acd1 删除了哪些文件
git diff --diff-filter=D --name-only c363a14..568acd1 -- backend/app/

# 从 c363a14 逐个恢复这些文件
git diff --diff-filter=D --name-only c363a14..568acd1 -- backend/app/ |
  ForEach-Object { git checkout c363a14 -- $_ }

顺便修了一个配套问题:pyproject.toml 里缺少 hatchling 的构建目标配置,导致重启时包识别失败:

[tool.hatch.build.targets.wheel]
packages = ["app"]

最终用 fd146ac 完成了恢复,后端恢复正常。


教训

这次事故没有造成不可逆的损失,但它暴露了几个在使用 AI 辅助开发时需要特别注意的点:

  1. 不要让 AI agent 替你"信任"变更。Agent 报告 "7/7 成功" 不等于真的没问题。批量提交前,花 5 秒看 git diff --stat 能避免 50 分钟的事故恢复。

  2. 关键操作后立即验证。Archive 完就跑一下应用,不要等几个步骤之后才发现。把 smoke test 当作每个流程阶段的结束仪式。

  3. Git 是你的安全网。这次能在 10 分钟内恢复,完全依赖 Git 的 commit 历史。git checkout <commit> -- <paths> 是一个值得记住的命令。

  4. 流程设计也要考虑失败场景。Comet 流程的 archive 阶段缺少内置的验证步骤,这是一个可以被改进的点。


总结

这次事故本质上是 一个信任问题:人类对 AI agent 输出的"成功"标记产生了过度信任,跳过了本不该跳过的检查步骤。

AI agent 很强,但它不会对自己的错误感到不安。那个 "7/7 步骤成功" 不会告诉你它刚刚删掉了半个项目。

看一眼 diff,跑一下应用,这两件事永远值得做。