返回博客

架构师 Review 必须 grep 运行时,光看 Spec 会翻车

在多 agent 协作的开发流程里,有一个常见分工:一个 agent 负责按 spec 生成实现 prompt,另一个(架构师角色)负责 Review 这份 prompt 再放行。这个模式效率很高,直到我连续踩了两个坑——每次 Review 看起来天衣无缝,实现方却不断发回「你的 prompt 在实际代码里跑不通」。

五轮审核循环,每轮暴露一个新问题:调用顺序错了、JOIN 类型错了、DATETIME 精度有歧义、迁移文件路径不对、标识符匹配太松……每一个问题,grep 两行就能发现。

现象

架构师 Review 完一份实现 prompt,判断「spec 覆盖了,逻辑没问题,放行」。实现方拿去跑,发现实际代码的某个细节使得 prompt 的假设不成立,打回来。架构师修了那一点再放行,实现方跑了,又发现另一个细节——如此往复。

典型的几类反馈:

  • 「PUT handler 里 validateFieldsFOR UPDATE 事务之前运行,所以 spec 承诺的 409 根本触发不到,先被 422 拦掉了」
  • 「迁移 runner 扫的是 scripts/*.ts,你 prompt 里写的路径 src/migrations/*.ts 根本不会被执行」
  • _migrations 表存的是完整文件名,你的 SQL 用 LIKE '%slug%' 会误匹配未来的迁移文件」
  • 「DATETIME 是秒精度,created_at <= migrationTs 的边界条件在同一秒内保存的行上会分类错误」

根因

这些全是运行时地雷,不是 spec 能描述的内容。

ADR / spec 文档记录的是「应该怎样」,不记录「实际代码现在怎样」:

  • 中间件的调用顺序
  • SQL JOIN 类型对孤儿行的影响
  • 迁移 runner 的 glob 模式
  • 数据库字段的实际精度和约束
  • 标识符的存储格式(slug vs 完整文件名)

架构师 Review 只核对 spec 文本,把「实现细节交给实现方自己发现」,本质上是把 reviewer 该做的 grep 工作转嫁给了实现方——但实现方发现了问题之后,还得把结果传回来,再等一轮审核。

坑:spec 正确 ≠ prompt 可执行

审核 prompt 时,「spec 逻辑覆盖了」和「prompt 在实际代码上可以正确执行」是两件事。两者之间的缺口,就是运行时地雷区:调用顺序、SQL 语义、路径约定、精度边界——这些只存在于代码里,不存在于 spec 里。

正解

放行一份实现 prompt 之前,针对 prompt 依赖的具体运行时事实做定向 grep,而不是通读整个仓库。

1. 验证调用顺序

如果 prompt 依赖「步骤 A 在步骤 B 之前」(比如加锁在校验之前),直接读对应的路由 / controller 入口,看当前实际调用顺序:

# 找 PUT handler 里哪个先执行
rg "validateFields|FOR UPDATE|lockCheck" src/app/api/workflows/route.ts

如果当前顺序和 prompt 假设相反,必须在 prompt 里明确要求重排,而不是假设实现方会自己调整。

2. 验证 DB schema 和 SQL 语义

# 确认字段实际约束
SHOW COLUMNS FROM your_table;
 
# 确认索引名称和列顺序
SHOW INDEX FROM your_table;
 
# 确认 JOIN 类型:INNER JOIN 会丢弃孤儿行,LEFT JOIN 才能捕获
rg "JOIN workflow_nodes" src/

3. 验证 runner / 测试框架路径

# 迁移 runner 实际扫哪里
rg "glob|migrate-\*|migrations.*\.ts" scripts/migrate-runner.ts
 
# vitest 实际扫哪里
cat vitest.config.ts

4. 验证标识符存储格式

# _migrations 表里存的是完整文件名还是 slug?
rg "INSERT INTO _migrations|\.name" scripts/migrate-runner.ts

如果存完整文件名(0012-add-column.ts),而 prompt 让你用 LIKE '%add-column%' 查,就会在未来有同前缀的迁移文件时误匹配。

正解:grep 具体地雷点,不是通读仓库

Review 时的 grep 目标不是「读懂整个项目」,而是逐一验证 prompt 依赖的每一个运行时事实:这个函数现在第几行调?这张表的字段实际是什么类型?runner 实际扫的路径是什么?把这些事实贴进 review feedback,实现方就能零歧义执行。

反模式:校验器的双重语义

还有一类坑更隐蔽——校验器同时承诺了「迁移时刻的快照正确」和「迁移后任何时刻也正确」。

一旦用户在迁移完成后的同一秒内触发了一次写入,新产生的行 created_at = migrationTs,被分类器当成迁移前的老数据处理,校验逻辑报错。DATETIME 秒精度,边界就在这里。

修法:让校验器只承诺一个语义——「迁移完成后立即执行一次验证」,不要同时兼顾「持续监控」。单一职责,边界清晰。

校验器 / 断言要单一语义

「迁移后立即验证」和「运行时持续断言」是两个不同的职责,混在一个校验器里会在时间边界上互相打架。分开写,各自的前置条件才能成立。

一句话外卖

Spec 描述意图,代码才是地图——审核别人的实现 prompt 前,grep 那几个具体的运行时事实,比事后来回五轮便宜得多。