# 统一失败分流规范（Failure Triage）

> 全框架唯一的**批量失败首轮分流**规范。解决两个对称的时间黑洞：把 N 条自动化失败逐条当 Bug
> 全流程处理（误报淹没真问题），或重跑变绿全部放过（真回归漏网）。一轮执行的失败集合先按四类
> 归类、逐条给依据、路由去向，再进入各自下游。
>
> 失败处理的三层能力栈，本文件只占中间层：
>
> | 层 | 职责 | 归属 |
> |----|------|------|
> | 运行时技巧层 | 执行中单条失败的即时定性（first-run-flaky 规则、等待策略） | 各执行 skill 工程约定（如 playwright-conventions 第 11 节） |
> | **分流层（本文件）** | 一批失败的首轮分类 + 路由去向 | 消费方在失败 ≥3 条时加载本文件 |
> | 深挖层 | 已确认 Bug 的根因/影响/Severity/修复建议 | `bug-analysis` |

## 1. 触发条件与输入输出

- **何时使用**：一轮执行（自动化全量 / CI 夜间任务 / 回归清单执行 / 回归复验）结束后，失败条数 **≥3 条**。1–2 条失败不值得分流开销，直接按执行 skill 单条流程处置。
- **输入**：本轮结果清单（TC 编号 × 通过/失败）+ 失败现场产物（trace / 截图 / 控制台日志 / API 请求响应记录 / JUnit results.xml 等结构化输出）
- **输出**：`{项目}/失败分流_{日期}.md`（模板见第 6 节）——逐条给分类 + 依据 + 去向；其结论分别流向上游各 skill 与测试报告对应章节
- **追加式留存**：分流文件按日期累积不清除——它是 D 类跨轮追踪的最小数据形态（见第 5 节），不需要额外数据库

## 2. 四分类定义（+U）

| 类别 | 判定语义 | 典型形态 | 定类最低证据 | 去向 |
|------|---------|---------|-------------|------|
| **A 真缺陷** | 产品侧行为与预期不符且变更非预期；实现未变而结果变了同样归此 | 断言失败但预期仍有效；数据不一致；状态卡死 | E3 运行证据 + S 级复核通过（第 4 节） | 执行 skill 报告 §3 记 Bug 条目 → 根因五字段移交 `bug-analysis` |
| **B 资产问题** | 失败由**测试资产侧**原因造成，产品行为无缺陷：B1 产品变更属预期但用例预期未跟上；B2 用例自身写错（脚本选择器永久失效、断言抄错字段、步骤拼错） | expected diff 恰为新文案/新默认值；页面重构后选择器过期 | B1 必须附**变更依据**（commit / 需求文档章节或用户裁决）；B2 给出写错位置 | 更新用例或脚本：B1 → `test-case-writing` 增量修订并留变更依据；B2 → 就地修正脚本 |
| **C 环境与依赖故障** | 失败由被测系统之外的运行环境造成：服务不可达、证书/账号失效、部署进行中、共享数据被污染 | HTTP 5xx 密集、连接拒绝、登录态全挂、同批大面积同形态失败 | E3 错误形态聚集 + 单一环境事件定位 | 记环境事件（一条），修复后**受影响批次原样重跑**（见第 5 节反吞没条款二） |
| **D 不稳定（flaky）** | 同一输入结果不定：竞态等待不足、清理不彻底、时序敏感 | 首跑失败原样重跑通过；历史翻灯交替 | E3 重跑对照（重跑只用于定性，不算通过） | 按 owning skill 工程约定处置（短期 fixme + 排期修根因），分流表跨轮追踪（第 5 节） |
| **U 无法定类** | 证据不足或信号互相矛盾的显式未知 | 现场产物缺失无法复核；两类信号冲突 | — | 测试报告 §6 未闭环事项，人工判断；**不许硬编结论** |

> 与既有三分法的关系：`api-testing` 运行纪律的"系统 Bug / 环境问题 / 用例自身错误"三分对应
> 本表的 A / C / B2——本规范是其全框架统一化，并补充了业界标配的 B1（预期变更）与 D（flaky）。

## 3. 判定树（先全局，后个体）

```text
输入：失败集合 + 失败现场产物

第 0 步 · 全局扫描（C 类前置排除）
│   为什么先做：环境故障会污染整批判断——环境坏了之后个体分析全是噪音
├─ 同批失败率 ≥50%，且错误形态趋同（同一 error type / 同一错误消息占比过半）
│  或登录态统一报错 / 目标服务不可达 / 5xx 密集
│     → 疑似单一环境事件：先定位它（部署中？账号锁定？数据污染？依赖挂了？）
│     → 确认后整批标 C 待重验，直接跳第 4 步收尾
└─ 无全局形态 → 进入个体路径

第 1 步 · 个体原样重跑（定性手段，不是通过手段）
├─ 稳定复现 → 进第 2 步
└─ 重跑通过 → D 候选（对照历史分流表翻灯记录可强化判 D，见第 4 节 G 表）

第 2 步 · A / B 区分（仅对稳定复现者）
│   该失败行为落在本次变更基线内吗？（git diff / 近期需求变更关联）
├─ 变更基线内 + 变更属预期（需求文档佐证或用户裁决）→ B1
├─ 变更基线内但变更不属预期 / 实现未变而结果变了 → A
├─ 疑似用例自身错误（选择器永久失效 / 断言明显抄错）→ B2
└─ 分歧拿不准 → ⏸ 呈现双方证据等用户裁决（意图问题：
    用户答复具有最终裁决力，evidence.md 三类裁决规则第三条）

第 3 步 · 收尾
└─ 以上全部未定 → U，进报告 §6 未闭环

第 4 步 · C 类收尾（反吞没条款二）
    环境修复后，受影响批次原样重跑
    ├─ 全部通过 → 该批次 resolved，事件单条归档
    └─ 仍有失败 → 失败者退出 C，回第 1 步重新个体定性
        （防止环境恢复把混入的真缺陷一并静默吞掉）
```

## 4. G/S 双级信号

> 口径声明：本节 G/S 与类型决策矩阵（`test-type-matrix.md`）同名同哲学，但**信号源不同**——
> 矩阵扫的是被测仓库代码（scan_signals.py），本表读的是**执行产物**（results.xml / 错误文本 /
> trace）。两者互不替代。

**G 级（机械可提取，聚合统计即可，无需 agent 语义理解）：**

| G 信号 | 提取来源 | 分类倾向 |
|--------|---------|---------|
| 同一 error message/type 重复 ≥3 条 | JUnit results.xml / 控制台文本聚合 | C |
| `HTTP 5xx` / `net::ERR_*` / `ERR_CONNECTION_REFUSED` / 超时类密集 | 错误文本分类统计 | C |
| 失败时间戳同秒级聚集 | results.xml timestamp 字段 | C |
| 登录/鉴权 helper 统一栈帧报错 | 失败堆栈公共帧比对 | C |
| assertion diff 中 expected = 文案/展示值，且近期有相关需求 commit | message 字段 × git log 对照 | B1（待补变更依据） |
| 本轮红上轮绿交替 / 条目曾标 fixme | grep 历史分流文件 | D |
| 选择器/元素不存在类错误且页面近期重构 | 失败消息 × git log | B2（待 S 级确认页面确已改版） |

**S 级（agent 读 trace / 截图 / API 日志做语义复核）：**

- 截图核对断言对象的实际语义：是时序未完成、还是数据真的错、还是页面结构确实变了
- API 响应体逐字段核对是否符合新需求（B1 变更依据的具体佐证）
- 自建数据残留检查（前序用例清理不彻底是 D 的常见根因）
- 用例步骤与实际页面动线比对（发现 B2 写错点）

**铁律：倾向 ≠ 结论。** G 级命中只产生预填候选；A 类定类必须过 S 级复核（E3 + 复核通过才允许记
Bug 条目）；B1 没有 G 表以外的独立变更依据不得判 B（见下节条款一）。这与矩阵 exclude 永不预填
是同一防橡皮图章原则。

## 5. 裁决规则与两条反吞没条款

- **A/B 分歧是意图问题**：按 `evidence.md` 第三类裁决规则，用户在澄清环节的明确答复有最终裁决力，
  后续阶段不得推翻；分歧呈现时给双方证据摘要，不自答（对齐 `qa` 编排 ⏸ Bug 定性检查点）。
- **条款一（防免检通道吞真 Bug）**：判 B1 必须给出具体变更依据——commit hash、需求文档章节、或
  用户裁决记录三者之一。给不出的一律回 A/U 处理。"看起来像需求变更了"不是依据。这是对齐评测
  纪律中"GT 错标让飞轮朝错误方向持续优化"的同源风险：一次错误的 B 判定会让真缺陷以资产更新为名
  合法消失。
- **条款二（防环境恢复掩盖缺陷）**：C 类不是丢进回收站——环境修复后受影响批次强制原样重跑，
  仍失败者升 A 候选重新进判定树。禁止只说"环境问题已解决"就关闭整批。
- **D 类升级机制**：同一 TC 在历史分流文件中出现 ≥3 轮（`grep -l` 即可检索，这正是追加式留存的
  目的）→ 升级处置优先级：fixme 转为排期修复根因，不允许永久 fixme 化（覆盖虚减风险，口径同
  `coverage.md` 对死用例的处理逻辑）。

## 6. 产出物模板：失败分流表

落盘 `{项目}/失败分流_{日期}.md`，结论直接被下游引用（报告 §2 统计口径不变，§3 只收 A 类条目）：

```markdown
# 失败分流 — {日期}

- 来源：{哪轮执行：回归清单_20260827 / CI 夜间 full-run}
- 规模：{总数} 失败 {失败数}（分流阈值触发原因：≥3 条）
- 结论分布：A={n} B1={n} B2={n} C={n} D={n} U={n}

## 环境事件（C 类汇总，无则省略本节）
- EVT-1：{现象}｜定位：{单一根因}｜处置：{修复动作}｜重验：{批次与结果}

## 分流明细

| # | TC | 类别 | G 信号摘要 | S 级复核 | evidence | status | 去向 |
|---|----|------|-----------|---------|----------|--------|------|
| 1 | TC-02-03 | A | 断言 stable diff，无聚集 | 截图核对：优惠金额确实双扣 | level: E3, source: bug-001-02.png | fact | 报告§3 BUG-001 → bug-analysis 五字段 TODO |
| 2 | TC-04-01 | B1 | expected=新版文案；关联 commit a1b2c3 | 响应体字段与新需求一致 | level: E3+E1, source: 需求 v2.3 §4.2 | fact | test-case-writing 增量修订（附依据） |
| 3 | TC-05-02 | U | 无聚集 | trace 缺失无法复核 | level: E0, source: 仅用户口述 | hypothesis | 报告§6 未闭环，找{谁}要 {什么} |
```

- evidence 字段格式遵从 `evidence.md` 第 4 节；status 取值同其第 3 节（fact / inference /
  hypothesis…）——**没有证据支撑的分类行视为无效行**
- C 类事件单列汇总而非按 TC 展开：环境故障是一因多果，逐 TC 重复记录只会制造噪音

## 7. 加载约定与其他 skill 的边界

**加载时机**（消费方在工作流中的标注方式，遵循 core 引用双形态约定）：

| 消费方 | 挂载点 | 时机标注 |
|--------|--------|---------|
| `automated-e2e-testing` | 工作流二之前 | 一轮执行结束失败 ≥3 条时（此时加载本文件），A 类才进证据收集与报告条目 |
| `api-testing` | 运行与验证节 | 失败 ≥3 条时改走批量分流，替换单条"先分辨"流程 |
| `regression-testing` | §4 结果衔接 | 回归多失败先分流再同步 Bug 状态，防把 B/C/D 误刷成复验轮次 +1 |

**边界速查：**

| 场景 | 归属 |
|------|------|
| 执行中发现单条失败的即时定性（first-run-flaky 判定、等待策略） | 各执行 skill 工程约定 |
| 一批失败的首轮分类与路由 | 本文件 |
| 已确认 Bug 的根因 / 影响 / Severity / 修复建议 / 回归建议 | `bug-analysis` |
| 修复合入后该跑哪些回归用例 | `regression-testing` |
| B1/B2 导致的用例与脚本修订 | `test-case-writing` / 执行 skill 的资产维护流程 |
| 类型域专项外部工具结果的回收 | 报告 §7（handoff 协议），与本文件无关 |

## 8. Common Mistakes

| 错误 | 后果 | 正确做法 |
|------|------|---------|
| 每条失败都当 A 记 Bug | 误报淹没报告，开发信任崩塌，triage 声誉归零 | 先全局扫描再个体定性；A 过 S 级复核才落条目 |
| 重跑变绿就放过（不标 D 不追踪） | flaky 混入绿灯名单，覆盖虚减，真回归夹杂其中随机漏网 | D 进分流表跨轮追踪；≥3 轮升级修根因 |
| 判 B1 却给不出变更依据 | 免检通道吞掉真缺陷，且以"资产更新"合法消失 | 条款一：无依据一律回 A/U；问用户 |
| C 类说一句"环境问题"就关整批 | 环境恢复后混入的真缺陷被静默吞掉 | 条款二：受影响批次强制原样重跑，仍失败者重新定性 |
| 把 G 级命中直接当结论报出 | 机械预判成为橡皮图章 | 倾向≠结论；A 必过 S 级复核（同矩阵 exclude 永不预填） |
| 分流行不给 evidence/status | 不可复核、不可续跑，后续阶段无从消费 | 无证据的分类行视为无效行 |
| U 类硬编一个类别交差 | 显式未知变隐性误导，人工兜底线索丢失 | U 进报告 §6 未闭环，注明缺什么证据、找谁要 |
