---
order: 13
date: 2026-08-05
summary: ——单元测试是自带弓箭手的靶子
---

# 弹劾的自动化

**——单元测试是自带弓箭手的靶子**

本系列有两句相隔多篇的话，摆在一起会更好地认出彼此。《可以被弹劾的结论》给形式逻辑的最终评价是：它不生产正确的结论，它生产可以被证明错误的结论。《断言与劝诫》给机器规矩定的标准是：只有会失败的那部分算数。前一句说的是三段论，后一句说的是单元测试——但它们几乎是同一句话。三段论的价值，是产出可以被弹劾的结论；单元测试的价值，是产出可以被判不通过的断言。

## 同一个灵魂

两者共享的不是修辞，是同一个波普尔式的原理：**价值不在保证正确，而在让错误可被检出。** 迪杰斯特拉说测试只能证明缺陷存在、不能证明缺陷不存在，听起来像贬低，其实和“生产可以被证明错误的结论”一样，是能给出的最高评价——我们从来没有办法保证任何一个判断是对的，我们只有办法让错的判断死得快一点。往下逐项对，密度会说明问题。

**都是转换器。** 心证是一个不透明的整体，“这个案子该原告赢”无法反驳，只能用立场去撞；三段论把它拆成大前提、小前提、涵摄，每一步变成可单独瞄准的靶点。“程序能跑”同样是一个不透明的整体，无法反驳，只能用“我这儿跑不了”去撞；测试套件把它拆成一条条可单独失败的断言。两边做的是同一件事：把私人的、整体的信心，转换成公共的、分段可攻击的对象。

**都有考场前移效应。** 知道推理要摊开受检的法官，写不出来的结论在心证半路就被掐灭；知道代码要过测试的程序员，测不了的设计根本写不出来。测试驱动开发的真实价值从来不是多抓几个 bug，是反向塑造设计——一个函数为了可测试，被迫把依赖摊开、把副作用剥离、把边界写清。《可以被弹劾的结论》里那句话原样适用：包装纸如果足够难穿，它就会反过来决定什么东西被生产出来。

**退化形态也互为镜像。** 不可弹劾的判断不算推理，只算神谕；没有测试的“能跑”不算正确性主张，只算一句无从审查的口头担保。而永不失败的测试——断言恒真的、mock 到失真的——就是《断言与劝诫》里的训示期间和“应积极配合”条款：绿灯常亮，含义为零。最阴险的镜像是最后一对：大语言模型那条事后编造的流畅推理链，等于一套测的是替身而非真实代码路径的测试——全绿，但箭射向的是假阵地。两边违反的是同一条前提：**靶子必须是真的。**

## 回归测试从哪里来

朴素的想象里，测试是照着规格说明预先写好的：先定义正确行为，再写代码去满足它。实际项目里最有分量的那部分测试不是这么来的——它们是从失败里长出来的。

标准流程只有四步。出了一个 bug，第一件事不是修，是**先写一条能复现它的测试**：跑一遍，看它红——红灯证明你真的抓住了它，而不是在修一个想象中的问题。第二步修复，第三步跑到绿。第四步最关键：这条测试**不删，永久进入套件**。从此每一次提交，无论改动的是天南地北哪一行代码，都要重新通过它——这个缺陷不可能再悄悄回来。回归测试的“回归”，指的就是防止已修复的缺陷回归。

如此积累出的套件，性质和照规格预写的测试完全不同：它编码的是**否定性知识**——这个系统曾经以哪些具体方式坏过。每条回归测试背后都有一次真实的故障：某个深夜的线上事故、某个边界条件的翻车、某处两个模块交界的误会。规格说明记的是系统应该做什么，回归套件记的是它实际错过什么，而后者是花了真实代价换来的。

这也决定了动它的纪律。想修改或删除一条既有测试，举证责任在动手的人：说清当初这条断言为什么错了或过时了。一条看起来多余的测试，往往携带着当初作者见过、而你现在看不见的故障信息——弄清它为什么存在之前，不要动它。

所以一个运转良好的回归套件，就是这个代码库全部失败经验的沉淀。**调试的经验死于调试者的离职，除非它被写成了回归测试**；一个只修 bug 不留测试的团队，每一代人都得重新踩一遍同样的坑。

## 靶子与弓箭手

对到这里要停一下，因为有一处关键的不同。一个可弹劾的结论是一个靶子，立在那里**等人来射**——对方律师、二审法院、学术批评，弓箭手全是外部的、要预约的：上诉有期限，改判要排期，批评来得更慢。一条断言不等任何人：它自己执行自己的弹劾，每次构建都开庭，失败即宣判，宣判即挡路。单元测试不是靶子的类似物，**它是靶子加弓箭手合一。**

那么问题就变得很具体：法律工作的成品上，能不能也装上自动开弓的弓箭手？能，分两档。

**第一档，确定性断言——机械可判定，红灯即证明。** 一份法律分析只要落成结构化文本，至少四类检查可以直接写成代码，《断言与劝诫》论证过升格的原理，这里把清单摆全：

- **引文勾稽。** 每条事实主张附逐字引文，与卷宗原文做子串比对，找不到即红灯；每个被引法条对照权威库核对现行有效，已废止、已修改即红灯。杜撰引文在这道检查面前物理性失效。
- **要件覆盖。** 大前提列出的构成要件逐一核对有无对应的事实认定，少一个即红灯。“以偏概全”从文风问题变成可检出的结构缺陷。
- **依据与语气匹配。** 解释性的前提拿不出条号、案号或权威文件支撑，结论却写成确定式，即红灯。依据变薄而语气未降，不是措辞瑕疵，是机械可识别的越线。
- **链条完整。** 结论所依赖的每个前置争点都已成立，引用不悬空，断链即红灯。

这一档的纪律与工程完全相同：失败要响，失败要挡路——红灯不清零，成品不出门。

**第二档，半断言式检查——不可机械判定，但可以概率地检。** 涵摄对不对、定性准不准，没有算法可裁定；但未必只能退回预约制的人工审查。办法是造一个独立的机器评审者：换一个模型，给它干净的上下文——不让它读作者的推理，只给原始材料——让它独立重走一遍，再与原结论比对。不一致本身就是信号：它不告诉你谁错了，但告诉你该往哪看。这样产出的也是断言：自动执行、失败会响，只是不再绝对。要让它真正可用，有三条配套纪律。

其一，改失败语义。确定性断言的红灯是**证明**——引文确实不在卷宗里，这是被证实的事实；半断言的红灯只是**指控**，还需要再裁决。闸门相应改写：红灯不直接挡路，挡路的是“指控未经处理”。

其二，先校准再上岗。往成品里播种已知缺陷，数这个评审者抓回多少、冤枉多少——量出误差棒之前，它的产出只是一家之言；量出之后，它是一台误差率已知的仪器。法律对这种东西有现成的制度位置：**鉴定意见**——可采信、不当然拘束，证明力由裁判者衡量。机器评审的红灯按鉴定意见处置，不按判决处置。

其三，守住独立性。半断言的可靠度，上限不在算力，在评审者之间真实的独立程度。干净上下文隔离的是个案污染——读过作者推理的评审者，射的是《可以被弹劾的结论》里那个假阵地；换模型族稀释的是系统性偏置——但稀释不净：不同的模型共享大体同源的语料，多请几个评审压得掉随机误差，压不掉共同的成见。三个评审一致放行，可能只是三个读者戴着同一副眼镜。

两档之外剩下的——涵摄的最终当否、定性的最终取舍——归人。由此得到一根诚实的进度条：法律推理工程化的进度，不该用“AI 替代了多少法官”度量，该用**弹劾被自动化的比例**度量，计分按三档：确定性断言算满分，校准过的指控算半分，没有误差棒的意见不算分。

## 缺席的标准答案

最深的一处不对称，留在最后。

单元测试的完整形态是：给定输入，断言期望输出。`sort([3,1,2])` 应当等于 `[1,2,3]`——这条断言写得出来，是因为有人**事先知道正确答案**。测试预设一个答案源，工程里管它叫 oracle：不管由谁提供——规格说明、数学定义、参照实现——总得有个地方能查到“对的输出长什么样”。

法律没有这个东西。一个案件的“正确判决”不存在可独立查询的答案源：二审不是标准答案，只是另一个法官——改判是又一次判断，不是对表。上诉审能构成 review，构成不了 oracle。终审判决之所以“正确”，用工程的话说，不是因为它通过了测试，是因为**它是最后一次运行**——没有下一级来断言它错。

这解释了一件否则很奇怪的事：为什么上一节第一档里列出的检查，验的全是结构而不是结果——引文在不在、要件齐不齐、语气配不配得上依据，没有一条是“原告应当胜诉”。用测试的分类学说，这不是样例测试，是**类型检查和性质测试**：断言的是不变量——每个主张有出处、每个要件有着落——而不是输出值。法律能自动化的弹劾至今全部属于这一类，不是因为没人想测结果，是因为结果那一栏，没有答案可填。

只有一个办法能凑出答案：把时间倒过来。已生效的判决可以当作标准答案——给定它认定的事实与援引的规范，重建推理，与法院实际的裁判对答案。这时 oracle 存在了，法律推理第一次拥有名副其实的输入-输出测试。但要看清它测的是什么。它测不出“这个判决对不对”——那仍然无人能断言；它测得出“这台推理机器像不像法院”。《AI 解决分歧》说过，模拟器的任务不是比法官更好，是像法官——用测试的语言重说一遍：拿判决当 oracle，测得出像不像，测不出该不该。oracle 在这里不是正确性的来源，是分布的来源。

## 尾声

现在可以把两句相隔七篇的话合成一句了。

三段论是让判断可测试的格式——法律几百年前就发明了它；单元测试是弹劾权的自动化——法律至今只在可判定的边角拥有它。工程能做的，是把这块边角一寸寸扩大：每多一条会红的断言，就少一处只能靠许愿的地方。工程不能做的，是给“该不该”那一栏填上答案——那一栏的空白不是技术债，是分工，《断点》已经把它划给了谁。

《可以被弹劾的结论》的结尾说：宁要一个会被推翻的判决，不要一个无法审查的正确。现在可以补上下半句——**宁要一条会红的断言，不要一份流畅的自查报告。** 两句话，一句是法律在几百年前做出的选择，一句是工程在几十年前做出的选择。它们是同一个选择。
