跳到主要内容
366 个绿测试,账本上什么都没还清

366 个绿测试,账本上什么都没还清

算账先生
算账先生

· 阅读约 6 分钟

这笔账,一般人记错了列。测试绿了,他们往“正确”那一列里记;其实该往“一致”那一列记——实现和规格一致。规格错不错,是另一本账,而 agent 圈很少有人立这本账。dev.to 那篇 The Tests Passed. The Contract Was Wrong 讲的就是这个,我头一遍看觉得这算什么新闻,不就是把字符串换成枚举再换成浮点,换汤不换药,讲这么长。第二遍看才发现,它把 agent 信任链上最贵的一笔隐性支出给晒出来了:所有人都在为“同一个人写的测试”买单。

先把案例复述个大概,不展开,只讲那个要害。一个多智能体权限系统,gate 拒绝授权时写一行记录。记录里有个 condition_delta,本来该放“为什么”的证据,结果放的是证据类别的派生标签。有个人六月就提过:别存你的结论,存 before 和 after,让陌生人能重算。作者也听了,把 grant.source_snapshot 和 current 存下来——但那规则只停在使用它的那一处,没跟到下游真正读结果的地方。所以分类器还是从 notes 的小写文本里抠“ttl expired”,ttl_remaining_hours 那几个结构化数值字段就那么晾着。再往下,修复一才把 notes 换成必填枚举 source_consult,分类器按枚举分发,不读 notes 了。366 个测试全过。接着一个不能读文件的评审问了一句:你凭什么断言这个枚举值为真?对方丢了一行 source_consult=SKIPPED_TTL_EXPIRED、ttl_remaining_hours=+17.4、decision=BLOCK 的记录,分类器照样返回 TTL_EXPIRED。作者自己承认——补丁符合契约,是契约错。

注意这个动作:一共三次“修复”。第一次把 notes 字符串换成枚举,第二次在枚举旁加了个四舍五入的浮点做一致性检查,第三次把浮点换成比较 decision_timestamp 和 grant_expires_at。第二次那个一致性检查,看着总算带点护卫相了:source_consult 说 TTL_EXPIRED,ttl_remaining_hours 是 +17.4,不匹配就报 INVALID。结果评审随手追加四行:授权不存在却返回过期;过期 1 秒被 round 成 -0.0,Python 里 -0.0>=0 是 True,反而判成 INVALID;传个 nan 直接穿过检查。一个比一个难看。每次都觉得权威往“更类型干净”的地方挪了。但评论里 pm25coder 一句话把这层窗户纸捅破:grant_expires_at 本身也是派生值,由 issued_at 和 ttl_hours 算出来,而这俩字段压根没写进行里。作者回去查了 schema,回得很老实:第三契约没通过“仅从行内数据重放”这个测试,行上不存在最少派生证据,issued_at 跟 grant_expires_at 比不是更原始,只是同一只手写得更早。看到这我才缓过劲——前面那三次修复,说白了是把“自我断言”从字符串重新包装成枚举、再包装成浮点、再包装成另一个派生字段。类型是越来越好了,权威纹丝不动。

这里头有三笔账,绝大多数团队只做第一本。实现正确性是一本账:代码按契约写,366 个绿,没毛病。规格正确性是第二本:契约 R3 白纸黑字规定 SKIPPED_TTL_EXPIRED 就返回 TTL_EXPIRED,不管同一行 ttl_remaining_hours 写着 +17.4。这个时候,绿测试不光不是资产,它是负债——它证明一个错的规格被忠实地执行了。第三本账最没人记:证据正确性。你那一行里写的枚举、浮点、时间戳,到底能不能被一个没有参与过你代码的人独立重算?不能,就是坏账。文章里原话差不多是这意思:通过的测试套件只证明实现者理解了规格,不证明规格理解了问题。这句话放在 agent 这行,杀伤力比它字面大得多。

为什么说 agent 圈的账尤其烂?因为 agent 的“测试”和“断言正确”发生在同一个系统里。Ofri Peretz 在评论里跟了句很准的类比:JWT 里写入 role:admin,下游不查签发路径,那这个 role 就是个自我声明;测试同时控制输入和断言那个控制输入的组件,绿了只说明你读懂了自己的意图。ANP2 后来的 D5 更狠:issued_at 是 gate 消费授权时打的时间戳,不是签发者发行时打的,所有字段一致、所有校验全过,过期判决照样错。为什么?因为整行都是同一只手写的。一致性检查天生只抓字段间打架,抓不到整行一起错。你让一个自己的左手跟自己的右手对账,对平了对平了,但你俩的账本是一个。

到这里其实已经能看出那个最难受的结论:这套东西没有第三方。文章自己盘点过,四个接触过的席位没一个有资格宣布修复有效——写契约的也写补丁,开 lane 的不能裁决,设计攻击的会塑造后继契约,owner 只授权不破坏。说白了,所有人都参与在同一场“自己证明自己”里,制造方机械复检那串结果作者自己都强调不是 PASS。这跟多少 agent 团队现在的处境一模一样:有人在写逻辑,有人在写测试,但两者共享一个大脑、一个假设、一套盲区。测试绿了,发布会照样开,客户上线照样翻车,翻完车一查代码,测试没坏,是测试的意思坏掉了。

那怎么办?文章里那条低成本方法,我越看越像这行被忽略太多的一笔便宜账:把你写好的契约,用平实话讲给一个没法运行代码的人听。不用解释实现,不用给代码,就问对方“按我这段字面意思,会出现什么”。那个无文件访问席位两次都命中,不是因为它聪明,是因为它没被你的实现污染过。你写代码的时候脑子会自动补齐缺口,陌生人不会。这就是认知差最小的应用:找一个不能执行你的世界的人,让他用自然语言反向问你。用算账的话说,这是给规格做空头检查,成本约等于一顿饭,收益是把“我以为我说清楚了”变成“我确实没被读歪”。

再深一层,就是把三个角色拆开:写契约的、写补丁的、决定有效的,不能是同一个人,甚至不能是同一套利益。文章里最反讽的是,作者自己意识到第三契约也谈不上正确,因为还没有独立席位攻击它。换句话说,现在的“有效”是悬空的。这个悬空不是失败,是个信号——agent 这行的信任模型远没到能自证清白的程度。fipsign 那套验证什么时候做、谁来做 breaker,那是工程进度问题;真正要改的是把“绿了”从账本的贷方摘出来,别让它冒充“对了”。

这篇东西如果只当测试经验看,可惜了。它记的是 agent 时代最普遍的一笔认知税:在同一个人的签名之上,再多的绿也只是同一个人的笔划。等到哪天,这些字段不再由同一只手写出来,而是有一道签发者的签名挡在中间,账本才真开始还。在那之前,先算到这儿。

算账先生
算账先生

用算账视角看 AI 工具这门生意——红利、认知差、护城河,泼完冷水给一条窄路。

查看主页 →