# 一次红色构建里的归因课 > 一次红色构建里的归因课。68 个用例的套件,红了 1 个——偏偏是那条端到端的去重测试(跨素材去重:只保留一份物理文件,并把记录标记为重复)。失败摘要里没有断言文本,只有一句 XP - Canonical page: https://obelisk.club/blog/build-log-1462 - Author: Peter Zhang - Published: 2026-10-11 - Tags: build-log 一次红色构建里的归因课。68 个用例的套件,红了 1 个——偏偏是那条端到端的去重测试(跨素材去重:只保留一份物理文件,并把记录标记为重复)。失败摘要里没有断言文本,只有一句 XPC 连接错误("connection to service named …"):测试死在通往不变量的路上,不变量本身从未被评判。 红色构建里藏着两类长得一模一样的失败:契约真的破了;或者环境根本没起来。区分证据只有一处——失败文本命名了什么。命名"连接、服务、守护进程、注册表"的,是管道的判决,不是产品的判决。同一份日志还夹着系统层的连接噪声("Unable to re-register with Process Instance Registry"),而错误摘录恰好在 "Error Domain=NSC" 处被截断:截断保住了每次都相同的样板头,删掉了唯一会变化的那个字段——病因本身。这就是这类问题能一直存活下去的机制:日志看起来很吓人,信息量却趋近于零。 修复的顺序,而且顺序本身是承重的: 1. 先读失败命名的对象,再决定碰不碰代码——这一步就把"改断言"和"修环境"分成了两条路; 2. 给不变量一条不会死于服务连接的测试路径:在服务边界处接缝,让"只留一份、标记记录"这条规则可以不依赖外部服务被直接判定; 3. 修日志截断本身:失败记录该保留尾部(错误域和错误码),丢掉头部样板——保头删尾的截断等于把诊断信息删掉; 4. 用对照探针收尾:同一条用例单独跑一次,单跑绿、整包红,就是环境与尾部队列负载类的问题,不是这行代码的问题。 一分钟自检:打开你最近一次红色构建,找到失败用例的 issue 摘要,问一句——这句话命名的是我的产品契约,还是一根管道(连接、服务、超时、注册表)?如果命名的是管道,你的不变量还没有被任何东西评判过;先修能产生判决的环境,再谈代码。