跳转至

多次回放子集不能拼成一次全量通过

2026 年 9 月 2 日,对 20 个历史失败案例做全量回放和多轮子集重跑,同一批案例在相邻轮次里结论互相矛盾,当天结束后重定了通过率口径。

一天的回放时间线

全量 20 案:13 通过、7 失败,失败分两类——5 个产品终态错误、2 个协议失败。

重跑那 7 个失败案例:全部失败,但失败类别全部变成了框架失败,上一轮的产品终态错误一个都没有复现。再跑其中 5 个:4 个通过,只剩 1 个协议失败。同一批案例在相邻两轮里从"产品错误"变成"框架失败"再变成"通过",代码没有改动,两轮之间只有环境不同。

框架失败这一轮可以直接排除。回放结束后,汇总脚本按每份报告给失败案例归类,规则按顺序匹配(简化):

# 案例没有生成 report.json      → framework
# 终态分类含 "|upstream|"       → provider
# 终态不是 completed            → product_terminal
# 报告里有 driver 层错误        → protocol
# 其余 critical 断言失败        → product_terminal

framework 排第一位,含义是这一轮没有产出报告、案例没有真正执行。这一轮 7 个案例的日志是同一行:

run failed: read case.json: open <临时数据集目录>/case-010/case.json: no such file or directory

case 数据没有拷到 runner 读取的临时位置,7 个案例一个都没跑起来。上一轮的产品终态错误一个都没有复现,原因是这一轮没有执行;它的 7 个失败对产品结论不提供证据。剩下那 5 个案例重跑时,唯一协议失败案例的日志指出了挂点:

drive error: submit preference feedback: completed result has no preference comparison

剩下的 3 个案例又跑了四轮:前两轮全部因供应商失败,第三轮 1 个通过,第四轮 2 个通过。晚间再对最后两个案例单独跑:一个完整通过(含全部偏好断言),另一个仍然失败。

前两轮供应商失败的形态一致,3 个案例各执行两次,终态分类都是 UPSTREAM_UNAVAILABLE|upstream|runtime,答案为空:

case-015  ab  fail  provider  2
case-018  ab  fail  provider  2
case-019  ab  fail  provider  2

执行两次是脚本行为:首轮失败被归为 provider 时自动完整重跑一次,第一次的日志保留。两轮、两次尝试都落在同一个上游失败分类上,之后轮次恢复通过,这两轮归为当时上游不可用,不计入产品缺陷。

唯一稳定的信号

所有轮次叠起来,稳定的现象只有一个:那个始终失败的案例,从凌晨的全量轮到晚上的单案轮,七轮以上没有一次通过,失败类别在协议、供应商、偏好断言缺失之间漂移。它最后一次失败是任务已完成,但结果里没有双候选比较,驱动提交偏好时失败,属于结果结构问题,任务完成本身发现不了。

这个案例属于 A/B 组,脚本在任务完成后还要代它提交历史偏好反馈。下午几次单跑里任务没有完成,终态分类是上游不可用,记供应商失败;当时偏好反馈同样提交不了,driver 报错:

drive error: preference feedback requires completed final task

当天靠后的两次单跑里任务真正完成了,终态、答案非空、每请求唯一终态、无失败 job 这些完成类断言全部通过,唯一失败的是 preference_presence,driver 报错:

drive error: submit preference feedback: completed result has no preference comparison

失败类别漂移的原因是各类失败按当轮报告归到不同分支:任务没跑成记框架,断在上游记供应商,跑完了但协议步骤失败记协议。就这个案例而言,下午的供应商失败是环境,傍晚的协议失败是结果结构问题;它全天失败多次,只有结果结构这一条是稳定缺陷。

任务完成发现不了这个问题,是因为完成类断言只查终态和答案;结果里有没有双候选比较由 preference 组断言单独检查。这个案例的任务能完成、答案非空,但结果里没有双候选比较,驱动在提交偏好反馈时直接报错。同一天傍晚其他 A/B 案例也有完整通过的记录,实验配置、双候选非空、双候选身份隔离、反馈持久化这些偏好断言全部通过,说明当天本地栈和偏好链路本身能工作,问题出在这个案例的结果结构。

其余案例的失败大多是环境性的:框架失败、供应商失败会随轮次消失,不是稳定的产品缺陷。

统计口径

把每个案例最好的一次结果挑出来合并,当天能拼出一份"20 案全过"的成绩单,但没有任何一轮真实跑出这个结果:没有一轮在同一版本、完整样本上全部通过,那个始终失败的案例也不存在可拼的通过轮。

拼不出来的原因在各轮内部:框架失败那轮案例没有执行,供应商失败轮是瞬时上游问题,而且每轮跑之前脚本都会重启本地栈、按组切换偏好开关,样本范围逐轮缩小。同一案例在不同轮里从框架失败变成供应商失败再变成通过,每次变化都对应各轮环境差异,不能跨轮合并。

另外脚本约定 provider 首轮失败时自动重试一次、首次日志保留。重试消除了某次瞬时错误,不等于原失败记录失效,这条也进了口径。

定下的口径:每轮记录保留代码版本、样本范围、实际尝试和失败分类;重试消除了某次瞬时错误,不等于原失败记录失效;子集重跑只能作为单个修复的证据,不能计入通过率分母;发布状态以"同一版本、完整样本、单次执行"为准。重新计算评分不能代替重新运行。