助手交回一段自洽、有测试的代码,可它解决的问题不是提出的那个。这时要读的是意图,不是每一行。
如果是轮到自己审别人的请求、不知道从哪读起,直接看读改动的顺序。
评审的人能不能用一句话说出「这次改动要解决什么问题」,并且指出它在改动里对应哪几行?
答不出,说明只读懂了代码、没读懂意图。先退回让提请求的同学补说明或补规约链接,再进入代码评审;意图不明时在下面点批准,等于替他猜了这一次。
四步,不能换顺序。第二步最容易省,代价也最大:一个「顺便」重排了三个目录的改动,会让后面所有改动差异都变得难读。
git diff --stat origin/main...HEAD。先看清单再进细节;出现与标题无关的文件,当场问它和本次的关系。把这份清单放进仓库,评审时对着问。问题本身不带评判,答不上来才是信号:每问一句,要拿到一个能指到文件或行号的答案。
可以直接抄进仓库,评审时逐条问。
# 意图审查问句 ## 每次改动都要问 1. 这次改动对应哪一份规约或哪一条需求?给出链接。 2. 说明里的每一句「做什么」,在改动里对应哪几行? 3. 删掉了哪些原有行为?删的依据是哪一条? 4. 有没有与本次主题无关的文件被顺带改了?它和主题是什么关系? ## 出现默认值、阈值、文案时问 5. 这个默认值是几?谁定的?改它要动哪个文件? 6. 这个文案在别的页面出现过吗?两处不一致时以哪一处为准? ## 出现失败路径时问 7. 失败路径返回什么?和成功路径的返回有什么可观察的区别? 8. 这个错误会不会把内部信息(表名、地址、堆栈)带给调用方? ## 涉及外部状态时问 9. 这段逻辑依赖时间、随机数、网络或并发吗?测试里怎么把它固定住? 10. 如果这段代码今天上线,第一个会踩到它的用户是谁?
边界:这份清单用在涉及行为变化的改动上。纯格式、纯注释、依赖升级不用逐条问,按审查些什么的分工表交给门禁就行。
问:这次改动对应哪一份规约? 答:实现了笔记列表分页,改动在 app/api/notes.py。 问:删掉了哪些原有行为? 答:没有删除原有行为,本次只做新增。
认它的办法:看答案是在回答问题,还是在复述改动。问「对应哪份规约」,答的是「做了什么」;问「删了什么」,答「没删」——后者只有真读过差异才说得准,助手是顺着问句补的。每条答案都要能指到文件或行号,指不到就按未答处理。
这四类的共同点是:出错时拦不住,事后也修不回来——数据已经错了、钱已经扣了、记录已经删了。所以它们不看测试结果,只看一件事:指定的人在合并前读过实现并留下记录。下面这份清单文件可以直接抄进仓库。
每季度检查一次「复核人」是否还在组里,换了人要改这一行。
# 高风险路径清单 判定规则:改动的文件命中下面任一条「路径」,就必须由该条指定的 复核人在合并前看过实现,并在说明里写下姓名、日期、依据。 ## 1. 权限与身份 - 路径:app/api/notes.py 的 _visible_scope() - 触发条件:改动涉及 scope_id 的来源、过滤条件、可见性判断 - 复核人:@张三(每季度轮换,当前负责人) - 判据:过滤条件只来自会话;不存在从请求体或查询参数取 scope_id 的路径 - 最低证据:一条跨 scope 的接口测试,返回 404 且正文与「不存在」一致 ## 2. 金额与计费 - 路径:app/service/billing.py - 触发条件:改动涉及金额计算、扣减、精度或舍入 - 复核人:@李四 - 判据:同一 order_id 重复提交只产生一笔扣减 - 最低证据:两次同 order_id 的请求,第二次幂等返回同一结果 ## 3. 数据删除与迁移 - 路径:migrations/、任何 DELETE / UPDATE 语句 - 触发条件:改动会修改或删除已有数据 - 复核人:@王五 - 判据:执行前有 SELECT 出待改行数;回滚步骤在预发库执行过 - 最低证据:迁移脚本 + 回滚脚本 + 预发执行记录 ## 4. 并发与对外兼容 - 路径:app/api/*.py 的响应模型、共享状态 - 触发条件:改动涉及共享状态、锁,或对外字段的增删改 - 复核人:@张三 - 判据:旧调用方不改也能工作;共享状态有锁或原子操作 - 最低证据:字段兼容说明 + 一条并发测试 ## 待办 - 并发写入同一行 note 的行为:本学期无压测环境,未查(记录于 2026-10-03)
这四类代码占全项目的比例很小,但漏审一次的后果是:写事故记录、订正数据、向用户解释。三样加起来比任何一次半小时的深审都贵。四类的底线判定见质量红线。
深审不是点个头。要留下三件事:谁看的、什么时候看的、依据什么。三样齐全,下一次才能复查;缺一样,出事那天所有人只能重新读一遍代码。写一行记录一分钟,比事后复盘便宜。
一次深审一份,文件名用日期加改动名。四行主体,缺一行按未审处理。
# 深审记录:笔记列表分页(PR #418) - 复核人:张三 - 时间:2026-10-03 15:20 - 依据:docs/high-risk.md 第 1 条(权限与身份) - 改动范围:app/api/notes.py:41-88、app/service/notes.py:12-30 - 结论:通过 - 看过什么:scope_id 只来自会话;分页游标不参与权限判定;不存在第二条读取路径 - 没看什么:并发写入同一行 note(无压测环境,已记入 high-risk.md 待办) - 出错影响:跨 scope 读到数据,不可逆,只能订正与通知
边界:记录不是签字仪式。写「看过什么」时要能指出具体文件和行号,写不出就说明还没看。这份记录和溯源与责任里的合并请求说明是两份文件:说明跟着改动走,记录跟着人走。
黑盒合并指的是:合并的人说不清这段代码怎么工作,但它在测试里是绿的。它有三种常见形态,每一种听起来都有道理。
| 形态 | 听起来像 | 为什么不行 | 改成什么 |
|---|---|---|---|
| 测试通过即合并 | 「用例都过了,先合上去吧」 | 测试覆盖的是写测试的人想到的情况;这四类路径的错法通常不在里面 | 按 high-risk.md 指派复核人看过实现,再合 |
| 助手说没问题 | 「这个模式很常见,不会错」 | 语气一样自信,事后分辨不出哪次该信 | 要求给出可跑的检查,而不是结论 |
| 没人看懂但先用着 | 「核心逻辑太绕了,先跑通再说」 | 核心链路上没人看得懂,等于以后没人能改它 | 让作者讲到评审的人听懂,或拆小到能听懂 |
「先合再补」不算处理办法——补的动作没有截止时间,仓库里会长期留着一段没人看懂的核心逻辑。看不懂时怎么提,写法见合并与审查的评论一节。