---
name: eo-test
description: |
  为某个 change 编写并执行测试（以其验收清单为锚），产出 test.md 报告。严禁修改业务代码。触发：给这个 change 写测试 / 出测试报告 / test.md / /eo-test。
  NOT FOR: 与 change 无关的日常跑测试或补单测（直接做即可，不产报告）。
---

# eo-test — 测试

以 change 的验收清单为锚编写并执行测试，产出结构化测试报告。核心目标是**验证**而非**修复**。

## 职能边界

1. **绝对禁令**：**禁止修改任何非测试相关的业务源码**。发现 bug 只记录并建议修复，不自行改源码。
2. **操作范围**：仅允许修改、新增测试文件与测试目录内容。
3. **输出目标**：测试代码 + `test.md` 报告 + 对话速报。

## 核心原则

1. **以 AC 为锚**：change.md §2 验收清单逐条推导——每条 AC 至少一份**验证证据**（不必是本 skill 新写的测试：implement 已留下且审计通过的测试、一次性执行记录都算数）；§3 各 TODO 的完成判据（如有）作为补充覆盖点。AC 规范见 [../eo-shared/ac-spec.md](../eo-shared/ac-spec.md)
2. **审计 + 补缺，不重写**：implement 落下的测试是本 skill 的**输入**而非空白——先盘点已有覆盖并审计其真实性，只为缺口编写。独立性来自**独立审计与独立执行**，不来自重新编写
3. **AC 决定验什么，代码决定拿什么验**：AC 是**断言**的来源，不是**输入**的唯一来源。只按 AC 文字正向推导，验的永远只是「AC 想到的路径」——AC 写的是用户视角的期望行为，不会写出 `""` / `null` / 越界值 / 并发时序这类输入，它们只存在于实现的分支、默认值与空值处理里。**再多跑几遍环境矩阵也发现不了 AC 没想到的输入**
4. **回归资产分层**：永久测试文件只给逻辑密集、边界多、会被后续变更反复触碰的验证点；其余验证点以一次性执行证据（命令 + 关键输出记入 test.md）作证——测试深度随风险浮动，与 AC 的「条数不模板化」（ac-spec）同一原则
5. **重验证的唯一执行者**：auto-heavy AC（起服务 / 多环境组合 / 点击流）由本 skill 跑并勾选，implement 不跑——环境矩阵在这里一次跑完，不在三个阶段各重演一遍
6. **验证驱动**：所有职能围绕「证明代码是否符合 AC」展开
7. **独立报告**：固定产出到 `eo-doc/changes/<change-id>/test.md`

## 前置条件

- **必须能找到 `.eo-project.json`**。同目录存在 `.eo-project.local.json` 时顶层字段覆盖合并（local 优先）。找不到 → 报错退出，提示运行 `/eo-project-init`
- `eo-doc/changes/<change-id>/change.md` 已存在，且相关代码已实现（status: implementing 或 reviewed）
- `tier: light` 的 change 默认不经本 skill（重验证出现即扩档，见 eo-implement 轻模式）。用户显式要求时以 §2 AC 为锚执行，但为**只读语义**：测试代码照常落库，结论走对话速报，**不写 test.md 进 change 目录、不动 AC 勾选、不改 status**；发现缺陷 → 已 archived 的走 /eo-fix

## 工作流程

### 阶段一：单元测试（审计 + 补缺）

1. **消费 lessons**：按 [../eo-shared/lessons.md](../eo-shared/lessons.md) §1 扫 INDEX 匹配 trigger，命中读「规则」节带入——**尤其是环境相关的项目 lesson**（起停命令、单次代价、环境由谁起属项目特异知识，只可能在项目 lesson 里，不在本 skill）
2. **盘点已有覆盖并审计**：读本次 diff（frontmatter `base_commit` 起算，或 `[<change-id>]` 前缀的提交，**含 implement 落下的测试文件**），建立「AC → 已有测试」映射；逐条审计已有测试的真实性——断言是否真实覆盖对应 AC、有无被弱化/删除、有无过拟合/硬编码特判。审计通过的**不重写**；测试代码问题由本 skill 直接修正
3. **提取缺口验证点**：读 change.md §2（AC 逐条）与 §3（TODO 完成判据，如有），对照步骤 2 的映射列出**无覆盖**的验证点清单；逐条标注 **light / heavy**（heavy = 起服务 / 多环境组合 / 点击流）与适合单测 / 需集成验证
4. **读实现取输入**：从步骤 2 已读的 diff 中，从**分支、默认值、空值与边界处理、类型转换**提取 AC 没写、已有测试也没碰、但代码实际会遇到的输入，补进缺口清单——AC 给断言，代码给输入（核心原则 3）
5. **补缺编写**：只为缺口写测试，遵循项目既有测试目录与命名约定；按**回归资产分层**（核心原则 4）取证据形态——逻辑密集 / 边界多 / 共享路径的落成测试文件，其余以一次性执行证据作证（命令 + 关键输出记入 test.md「一次性执行证据」节，不落测试文件）
6. **执行**：全量运行（implement 已写 + 本 skill 补写）收集结果
7. **失败分析**：测试代码自身写错 → 直接修正测试；业务代码 bug → **停手**，记录到报告并建议走 /eo-implement 修复循环

### 阶段二：集成 / 场景验证（重验证，一次跑完）

对 **auto-heavy AC** 与其余不适合单测的 AC（用户视角操作链、端到端行为），按其验证口径（「验证」栏，省略时按声明本身）描述的操作编写独立验证流程；捕获命令输出、退出码、运行结果作为执行证据。

**环境纪律**（详见 [../eo-shared/ac-spec.md](../eo-shared/ac-spec.md)「重验证的环境纪律」）：环境**假定已就绪**——先探测复用、**不主动停**，只在需要换环境组合时重启；**按环境组合分组跑**，一次起环境跑完该组合下的全部验证点，不为单条 AC 反复起停。

验证通过 → **勾选对应 auto-heavy AC**（本 skill 独有的勾选权）；light 项 implement 已勾不重跑，manual 项不碰。

### 阶段三：报告与速报（轮次留痕，追加不覆盖）

1. 按 [references/test-template.md](references/test-template.md) 维护 `eo-doc/changes/<change-id>/test.md`：
   - **首轮**（文件不存在）：全量写入，失败项同步建入 FAIL 台账（FAIL-x 编号跨轮稳定；根因区分 `implementation` / `test-harness`——测试代码错误由本 skill 修正后直接核销，不留给修复循环）
   - **复审轮**：**不重写报告**——先核销台账（`fixed` 项复测：过 → `verified`，仍失败 → 回 `open` 一句话说明；`verified` 后再失败 = reopen，刷新最近轮）；新失败建条（编号沿用同一序列）；在「速报」前追加 `## 第 N 轮记录（revision R · 日期）` 节，原地更新末尾速报。遇**无台账的旧格式报告** → 按当前内容一次性补建台账再继续
   - 台账写入权见模板 writer matrix：本 skill 建条与核销；`fixed` + 修复 commit 归 eo-implement 回写；用户当场裁决不修的项 → 状态置 `waived`（附原话要点，不阻塞归档）；历史轮次节不改；轮次编号全文件单调递增，跨 revision 不清零
2. **status 回退**：结论不通过且当前 status 为 `reviewed`（review 先过、test 后翻车）→ **当场置回 `implementing`** 并联动刷新 stub（回退边，见 [../eo-shared/conventions.md](../eo-shared/conventions.md) §3）
3. **对话速报（硬性——缺速报 = 流程未完成）**，报告写盘后在对话最后输出：

```
结论：通过 / 不通过（失败 x 项）［第 N 轮 · revision R · 基线 <short-sha>］
⚠️ 复发：<ID> 第二次失败（无则省略此行）
失败用例：
1. <一句话> — <用例/文件>
未覆盖 AC：<AC-x（原因）>；全覆盖则省略此行
下一步：<回 /eo-implement 修复 / 可进入 /eo-review（尚未审码）/ 可进入 /eo-archive（已审过码）>
（详细报告见 <test.md 路径>）
```

每条一句话加定位，不在速报里展开分析；全绿时压缩为「结论 + 下一步」两行。

## 关键约束

- **禁止跨权**：严禁修改业务逻辑代码
- **不重写已覆盖项**：已有测试审计通过的 AC 不重复编写；独立性靠审计 + 独立执行保证，不靠重写
- **测试独立性**：用例独立运行，不依赖执行顺序
- **不修改 change 的内容**：AC/TODO 的文字不动——发现写漏/写偏记录到报告并建议回 /eo-implement（其流程含「确认后就地补 AC」；循环内问题不出循环）。**勾选 auto-heavy AC 是本 skill 的职权**（勾是验证结果的落点，不是改 change）；light 项已由 implement 勾、manual 项归用户，两者都不碰
- **环境不归你所有**：探测复用、用完不停；按环境组合分组跑，不为单条 AC 反复起停
- **输入不只来自 AC**：跳过「读实现取输入」= 只验 AC 想到的路径，这正是重验证跑再多遍也漏缺陷的原因
- **证据完整**：关键场景必须有可验证的执行证据
