# 失败归因

## 一级分类

先做五选一，不要一上来就改代码或改断言。

| 一级分类 | 定义 | 允许动作 | 禁止动作 |
| --- | --- | --- | --- |
| `TEST_CODE_ISSUE` | 定位器、断言、等待时机、fixture 或测试搭建错误 | 修测试代码，保持原测试意图 | 弱化断言掩盖产品问题 |
| `PRODUCT_BUG` | 实际行为违反需求、契约或设计预期 | 输出 bug report，按 owner 修业务代码 | 把 bug 改写成测试通过 |
| `REQUIREMENT_CHANGE` | 规格、文案、流程或契约已明确变化 | 先更新真相源，再更新测试 | 不更新规格就改测试预期 |
| `ENV_OR_DATA_ISSUE` | 服务未启动、数据不完整、权限、端口、外部依赖问题 | 修环境 / 数据并重跑 | 删除测试或直接跳过 |
| `FLAKY` | 偶发、非确定性、重跑不稳定 | 收集证据，修等待/隔离/时序 | 用 `waitForTimeout` 掩盖问题 |

## 二级归因

在一级分类后，再细分 owner。

| 失败类别 | 对应一级分类 | 典型信号 | 归属方 | 修复目标 | 回归执行方 |
| --- | --- | --- | --- | --- | --- |
| `REQ_GAP` | `REQUIREMENT_CHANGE` | 缺少验收示例、业务规则含糊、没有可观察判定依据 | 产品 | 产品 / 需求负责人 | 原审查人或测试代理 |
| `TRACE_GAP` | `REQUIREMENT_CHANGE` | 需求未映射到 UI / API / 测试 / 证据 | requirements-trace | 追溯负责人 | 原审查人或测试代理 |
| `DESIGN_GAP` | `REQUIREMENT_CHANGE` | 缺少状态、选择器、交互或视觉规则 | 设计 | 设计负责人 | 原视觉 / 测试代理 |
| `CONTRACT_GAP` | `REQUIREMENT_CHANGE` | 缺字段、类型错误、错误码错误、鉴权规则不清楚 | 契约 | 契约负责人 | 契约测试者 |
| `FRONTEND_BUG` | `PRODUCT_BUG` | 按钮不可点击、路由错误、状态缺失 | 前端 | 原开发者 | 原测试代理 |
| `BACKEND_BUG` | `PRODUCT_BUG` | 500、业务规则错误、权限未生效 | 后端 | 后端开发者 | API 测试者 |
| `TEST_BUG` | `TEST_CODE_ISSUE` | 断言错误、等待不稳定、fixture 无效或误报 | 测试 | 测试作者 | 原测试代理 |
| `TEST_DATA_GAP` | `ENV_OR_DATA_ISSUE` | 缺少 seed、账号状态错误、数据重置不可靠 | 测试 / 数据 | 测试数据负责人 | E2E 测试者 |
| `ENV_BUG` | `ENV_OR_DATA_ISSUE` | 端口冲突、服务未启动、依赖缺失 | 环境 | controller / 操作人 | test-runner |
| `FLAKY` | `FLAKY` | 间歇性、非确定性失败 | test-runner | 对应 worker + 测试负责人 | 原测试代理 |
| `SECURITY_RISK` | `PRODUCT_BUG` | 认证、权限、密钥或敏感数据问题 | 安全 | 安全 / 后端负责人 | 安全审查者 |

## 归因记录模板

```md
### Finding ID

- 一级分类:
- 二级分类:
- 失败测试 / 命令:
- 责任方:
- 根因:
- 证据:
  - 日志:
  - trace:
  - screenshot / video:
  - network / console:
- 修复动作:
- 重新运行结果:
- 后续验证:
```

## 规则

- 不要默认把所有失败都归给前端。
- 先从 `repo-map`、`verify-matrix`、`acceptance examples` 和相关测试计划确认预期，再判断失败性质。
- 需求或追溯缺陷应回退给产品 / 追溯负责人，不应由实现者自行猜测修补。
- 契约缺陷应先在契约或对应 owner 流程中修复；不要在前端 / 后端绕过问题。
- 不要只靠代码评审就关闭 finding；应重跑最小相关测试。
- 提出 finding 的测试者 / 审查者应在修复后负责关闭它。
- 环境和网络失败除非超出重试预算并重复出现，否则不应视为产品失败。
- `FLAKY` 不是兜底垃圾桶；必须附带重跑结果和时序 / 隔离分析。
