eo-fix · git:20260724.5da3e6a · 2026-07-24 · sha256 2123f4ffae1b9909

eo-fix git:20260724.5da3e6aA

Immutable. This exact content is served forever at /api/v1/blob/2123f4ffae1b9909.

---
name: eo-fix
description: |
  bug 口喷入口:定位并直接修复。触发:修 bug / 有个 bug / 报错了 / 行为不对 / fix / /eo-fix。
  NOT FOR: 明确的业务变更(走 /eo-change);implement-test-review 循环内的反馈修复(归 /eo-implement 模式二)。
---

# 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)」;用户仍要改 → 这是需求变更,转 `/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(**auto-heavy 不代勾**,勾选权归 /eo-test;被本次改动弄脏的已勾项按 [../eo-shared/ac-spec.md](../eo-shared/ac-spec.md)「勾变脏即取消」处理),commit 带 `[<change-id>]` 前缀;改动影响其 acceptance.md 人工项的入口/行为 → 按 [../eo-shared/acceptance.md](../eo-shared/acceptance.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:<是/否>
```

## 关键约束

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

## 典型场景

**场景 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。