---
name: eo-fix
description: |
  缺陷修复方法论唯一入口：口喷 bug 定位直修；implement-test-review 循环内的反馈修复也走本 skill（循环内分支，原 impl worker 执行）。触发：修 bug / 有个 bug / 报错了 / 行为不对 / fix / /eo-fix。
  NOT FOR: 明确的业务变更（走 /eo-change）。
---

# eo-fix — Bug 修复

三层**按需付费**：默认快路 ≈ 直接修 + 30 秒记账；只有要推翻一个「可能是有意的行为」时才取证；只有定位不了才深挖。对一个 typo，本 skill 的开销趋近于零——任何不触发的层都不存在。

## 核心原则

1. **快路优先**：明显缺陷（报错、崩溃、数据错、无争议逻辑错）不查任何文档，直接修
2. **推翻行为前必取证**：现象是「应该/不应该」类语义分歧时，先花几百 token 确认该行为不是有意设计——防止静默推翻已确认的决策
3. **落点记账不豁免**：修复必须落进体系（勾 AC / commit 前缀），这是 archive 归集、看板、retro 统计的输入
4. **定位靠代码反查**：症状 grep 源码 + git log 前缀追溯，精确且便宜；禁止全局 grep eo-doc 正文
5. **深挖有门**：升级必宣告、结束必还原

## 前置

**必须能找到 `.eo-project.json`**。同目录存在 `.eo-project.local.json` 时顶层字段覆盖合并（local 优先）。找不到 → 报错退出，提示运行 `/eo-project-init`。

## 工作流程

### 第一步：分诊（一眼定路）

| 现象特征 | 走 |
|---------|-----|
| 「坏了 / 报错 / 崩了 / 数据不对」——对错无需文档裁决 | **快路**（第二步 → 第三步） |
| 「这里应该… / 为什么会… / 这个行为不对吧」——行为疑似有意实现、涉及业务规则或数值 | **取证路**（第二步 → 第四步） |
| 描述弥散、无从下手 | 第二步定位；仍无果 → 深挖（第五步） |

同时按 [../eo-shared/lessons.md](../eo-shared/lessons.md) §1 消费 lessons——同类坑踩过的，「规则」节直接给答案或作假设先验。

### 第二步：定位（代码反查为主，~500-900 token）

1. **锚定代码**：有症状字符串（报错文案 / UI 文案）→ 直接 grep 源码，几乎一步中的；没有 → 经 `eo-doc/agent-handbook/INDEX.md` 定位模块入口文件
2. **反查归属**：`git log --oneline -n 20 -- <嫌疑文件>` 看 commit 前缀——`[<change-id>]`（slug 或存量数字前缀）→ 相关 change 直达；`fix:` / `ui:` → 直改历史（无书面期望）；无前缀 → 存量代码
3. 需要书面期望时只读该 change 的 frontmatter + §2 AC，**不通读**

**辅路**（代码反查不灵时才用）：扫 `eo-doc/changes/INDEX.md`——活跃 change 置顶且通常只有 0-3 个，先看它们（刚做完的最容易坏）；不中再按关键词扫 archived 区。候选 >3 或全无匹配 → 追问用户。

### 第三步：快路修复

最小变更修复 → 用户给的复现步骤转成回归验证跑通 → 跳到第六步落点记账。中途发现行为其实可能是有意的 → 转第四步。修复代码**注释零溯源**：change/AC/finding 标记与修复辩护不进注释（[../eo-shared/conventions.md](../eo-shared/conventions.md) §2.6）。

**复现与回归都取最低成本层**：修前先在该层复现失败（这是根因判断的依据，也是「改完看起来对了」之外唯一的证据），修后在同层验通过。层的选法——纯逻辑用单测 / `node -e` 等价复刻（秒级），接口契约用一次请求，**确属集成 / UI 态才起环境**（环境纪律见 [../eo-shared/ac-spec.md](../eo-shared/ac-spec.md)）。不要每改一行就重新 build + 起环境。

### 第四步：取证路（仅语义分歧）

**证据瀑布**——期望行为不是单一锚点，按可得性降级取证：

| 优先 | 证据 | 作用 |
|------|------|------|
| 1 | 用户当下的口述 | 最高权威，永远存在 |
| 2 | 相关 change 的 §2 AC（若有） | 最优书面期望 |
| 3 | state/ 的记载 | **意图佐证**：行为被记为规则 = 曾被认为正常（state 是代码派生物，只能佐证意图，不能裁决代码对错） |
| 4 | git 归属（commit 前缀） | 追溯行为来源 |

判定与动作：

| 取证结果 | 动作 |
|---------|------|
| 行为查无出处（无 AC 声明、state 无记载）且按口述明显是缺陷 | 按快路修（第三步） |
| **行为是有意设计**（AC 声明过 / state 记为规则 / change 意图明确） | 停手告知：「这是 <change-id> 特意做的（AC-x）」；用户仍要改 → 纯外观 / 文案类按 trivial 直改，并顺手就地精化对应 AC 文本（意图不变）；涉及功能语义 / 交互逻辑 → 转 `/eo-change`（带上取证结论） |
| AC 写漏且 change 未 archived | 确认后先补 §2/§3 再修（Update preserves context） |
| state 与代码矛盾 | 文档陈旧 → 提示跑 `/eo-doc-manager sync`，以代码为准重判 |

**修复范围守界**：预估改动超出 trivial 量级（需方案权衡、动对外接口，判据见 [../eo-shared/granularity.md](../eo-shared/granularity.md) §2）→ 停手建议开 change，不硬修。

### 第五步：深挖模式（自动升级）

触发即向用户宣告：**「常规定位失败，进入深挖模式：会临时插桩/加日志/git bisect，结束后还原现场。」**

1. 读 [references/investigation.md](references/investigation.md)，按四阶段执行（固定复现 → 假设清单 → 二分排除 → 验证还原）
2. 调查记录写 `tmp/eo/fix/<date>-<slug>.md`（可丢弃工件）
3. 根因确认后回第一步分诊定路，再走修复
4. 根因有普适教训 → 提议 `/eo-project-record` 沉淀

### 第六步：落点记账（任何路都不豁免，~30 秒）

- 有相关**活跃 change** → 勾选涉及的 TODO/AC（人工项不代勾，勾选权归用户；被本次改动弄脏的已勾项按 [../eo-shared/ac-spec.md](../eo-shared/ac-spec.md)「勾变脏即取消」处理），commit 带 `[<change-id>]` 前缀；改动影响其 acceptance.md 人工项的入口/行为 → 按 [../eo-shared/acceptance.md](../eo-shared/acceptance.md)「失效与重置」取消该项勾选并注明原因；改动影响其 evidence.md 的入口/行为/截图事实 → 按 [../eo-shared/evidence.md](../eo-shared/evidence.md)「刷新与失效」同步刷新对应段
- 无 → 直改落地：commit 带 `fix:` 前缀（见 [../eo-shared/conventions.md](../eo-shared/conventions.md)），由下次 doc sync 兜底归档；cursor 落后超过 10 个 commit 时建议顺手跑 `/eo-doc-manager sync`

### 第七步：收尾速报

```
修复完成：<一句话根因>
- 改动：<file:line 级别的简述>
- 验证：<复现步骤回归结果 / AC 核对结果>
- 落点：计入 <change-id> / 直改（fix: commit <hash>）
- （取证时）行为出处：<AC-x / state 记载 / 查无出处>
- （深挖时）调查记录：tmp/eo/fix/<file>；建议沉淀 lesson：<是/否>
```

## 循环内分支（implement-test-review 反馈修复）

**适用**：`test.md` 有未决失败项，`review.md` 有 open P0/P1，或 `acceptance.md` 有「不通过」项。由 /eo-loop 派发到**原 impl worker** 执行（worker 复用纪律不变——本分支只是换方法论，不换人），或循环会话内直接调用。status 为 `reviewed` 时（产出阻塞结果的 skill 正常已按回退边置回；没置则此刻补）→ 先置回 `implementing`。

与口喷路径的差异只有两条：**免定位**（反馈报告即定位输入，跳过第二步）；**带核销职责**（第 1/5 步与交接速报）。分诊三路由原样生效——明显缺陷走快路；finding 与已确认 AC / 已钉决策冲突（「这个行为本来就不对」类）走取证路，防静默推翻；定位不了或链路连环失败走深挖，链路类缺陷用「全链审查」变体（见 [references/investigation.md](references/investigation.md)）。

0. **熔断检查**（修复动手前）
   - 凭报告与对话机械可判：同一 change 修复轮次 ≥3，或各轮失败触发位置互不相同（打地鼠信号）→ **停，不开始修复**，用户三选一：
     a) **豁免一轮**：放行本轮，change.md 末尾记「熔断豁免：<日期>」
     b) **卡点检查**：走下方子流程，按根因结论定出口
     c) **回炉**：转 /eo-change 回炉子流程（方案实质修订 + 重新确认）
1. **读取反馈**：同会话反馈已在上下文 → **不重读报告文件**；跨会话 → 只读报告的未决清单 + 结论，按 open 项定点读详情，不通读全文。根因为 `test-asset` 的 finding 不由本分支消费，交 `/eo-test`；本分支只处理业务实现项
2. **分诊定路 + 修复**：按 P0 > P1 > P2 逐一过第一步分诊表定路，各走快路 / 取证 / 深挖；修复代码**注释零溯源**（[../eo-shared/conventions.md](../eo-shared/conventions.md) §2.6）
3. **双向取证，取最低成本层**：每个缺陷**先复现失败、修后在同层验通过**——「改完看起来对了」不算证据；层选法同主流程第三步
4. 涉及的**自动 AC 就地重验**；被本次修复弄脏的**已勾** AC 按 [../eo-shared/ac-spec.md](../eo-shared/ac-spec.md)「勾变脏即取消」处理；修复改变了人工项的入口/行为 → 按 [../eo-shared/acceptance.md](../eo-shared/acceptance.md)「失效与重置」更新对应验收项；修复改变了入口/行为/截图事实 → 按 [../eo-shared/evidence.md](../eo-shared/evidence.md)「刷新与失效」同步刷新 evidence.md 对应段
5. **回写未决清单**：每个业务实现缺陷修复并同层验通过后，把对应报告清单行置 `fixed` 并填修复 commit——`verified` 由复审方核销，本分支不写
6. 修复提交带 `[<change-id>]` 前缀
7. **交接**：回原复审方核销（增量，不重开全文）。交付速报列：`反馈来源`、`修复 commit`、`受影响 AC`、`局部验证`、`下一节点`
8. 修复不开新 change；发现根源是方案/需求问题 → 停下告知用户，转 /eo-change **回炉子流程**（实质修订 + 重新确认；意图不变的口径精化不必回炉，就地补 AC 即可）

### 卡点检查子流程（熔断三选一选 b 时执行）

spawn 一个**新鲜上下文 subagent**（执行者自述不作数——修了 3 轮的 agent 是判断自己为何修不好的最差人选），输入按 manifest 给，**禁止默认通读报告全史**：

- change.md 全文
- test.md / review.md 的未决清单 + 结论 + open/fixed 项定点详情
- change-review.md 当前结论、acceptance.md 不通过项、implement.md 偏差记录（各自存在时）
- `[<change-id>]` 提交列表与涉及文件的 scoped diff、本 change 相关的未提交脏 diff

产出五分类根因 + 建议出口：

| 根因 | 出口 |
|------|------|
| change 方案/架构不合理 | 转 /eo-change 回炉子流程 |
| 链路失败语义残缺（向前写链，恢复面的洞逐次暴露） | 走深挖「全链审查」变体：枚举链上全部可死点 + 逐点恢复证明矩阵，按矩阵批量修 |
| AC 口径漂移（各轮按不同理解打回） | 回 /eo-change 钉死口径（意图不变的精化，不必回炉） |
| 纯实施质量问题 | 方向没错，建议豁免一轮继续修 |
| 测试基建/环境假失败 | 修基建；报告未决清单注明假失败供用户裁决 |

结论一行写入 change.md 末尾：`卡点检查：<根因>，<日期>`。**失败关闭**：subagent 起不了（槽位/工具不可用）→ 不得用执行者自述替代，记「卡点检查未执行」，用户在「稍后重试 / 直接回炉 / 单轮豁免」中裁决。

## 关键约束

| 约束 | 说明 |
|------|------|
| 明显缺陷不查文档 | 快路不做任何取证，速度对齐「直接修」 |
| 推翻行为前必取证 | 语义分歧不取证就改代码 = 可能静默推翻已确认决策，禁止 |
| 落点记账不豁免 | 三层里唯一的必做项 |
| 验证取最低成本层 | 能复现该缺陷的最便宜的层就是对的层（纯逻辑 → `node -e` / 单测，秒级）；起环境是最后手段，不是默认 |
| 定位禁全局 grep eo-doc | 代码反查为主，INDEX 辅路 |
| 修复范围守界 | 超 trivial 量级 / 需方案权衡 → 转 change，不硬修 |
| 深挖必宣告、必还原 | 插桩/日志/bisect 结束后全部还原 |
| 需求变更不伪装成 fix | **功能语义 / 交互逻辑**的期望变更就是 /eo-change 的事，哪怕改动很小；纯外观 / 样式 / 文案的期望变更不算——按 granularity §2 trivial 直改（前缀选择见 conventions §2.5） |
| 注释纪律 | 一切流程溯源标注（change 编号/slug、TODO/AC、finding P0-x/P1-x、FAIL-x）严禁进代码注释（溯源走 commit 前缀）；不写「为何正确」的辩护；提交前对新增注释自检一眼，见 conventions.md §2.6 |
| 循环内修复归本 skill | test/review/acceptance 反馈的修复走循环内分支（原 impl worker 执行）；eo-implement 无独立修复模式 |

## 典型场景

**场景 1 · 明显缺陷（快路，全程不碰 eo-doc）**：「导出报错了」→ grep 报错文案锁定文件 → 修 → 回归验证 → `git log` 见 `[batch-export]` 且该 change 活跃 → 勾 AC、`[batch-export]` 前缀提交。

**场景 2 · 有意设计被误报（取证路的价值时刻）**：「列表怎么把已归档的也显示出来了，去掉」→ 反查归属 `[list-archive-view]` → 该 change 的 AC-3 白纸黑字「归档项默认可见」→ 停手：「这是 list-archive-view 特意做的，要推翻它就是需求变更」→ 用户确认后转 /eo-change。**没有这一步，这个已确认决策就被静默推翻了。**

**场景 3 · 需求变更伪装**：「积分过期改成 90 天了」→ state 记载 30 天规则、代码一致——有意设计 → 转 /eo-change。

**场景 4 · 难缠 bug**：「偶发卡死，复现不稳定」→ 定位无果 → 宣告深挖 → 四阶段 → 根因回分诊 → 修复 + 还原 + 建议沉淀 lesson。

**场景 5 · 循环内打地鼠（全链审查）**：记账链 Test 连续 FAIL 且各轮触发点互不相同（终局等待面 / 锁权限 / 重试误判已入账）→ loop 打地鼠信号命中，用户选全链审查 → 原 impl worker 走深挖链路变体：枚举链上全部可死点，配不出恢复证明的点 = 洞 → 按死点矩阵批量修 → 台账置 `fixed`，回原 tester 复验。
