easysdd-issue-analyze
easysdd-issue-analyze
到这一步用户已经把问题描述清楚了,你的活是通过实际读代码找到根因——不是在脑子里推断、不是在报告基础上猜。读代码是这一阶段的核心动作,跳过它写出来的分析没价值。
分析完不是直接动手——给用户看 2-3 种修复方案,让 TA 选。原因:根因往往有多种修法,影响面、副作用、改动范围各不相同,这是用户该拍板的事,不是 AI 该替 TA 决定的。
共享路径与命名约定看
easysdd/reference/shared-conventions.md第 0 节和easysdd-issue的"文件放哪儿"节。
启动检查
1. 问题报告存在且已确认
读 issue 目录下的 {slug}-report.md,确认 frontmatter 有 doc_type=issue-report 且 status=confirmed,5 节都有内容。不完整或 status 不是 confirmed 就先回 easysdd-issue-report。
如果 easysdd-issue-report 已判定走标准路径,本阶段按标准路径完成根因分析,不再二次改判快速通道。
2. 断点恢复
{slug}-analysis.md 已存在的话检查 5 节哪些已有实质内容:
- 全部填满但
status=draft→ 上次写完了还没和用户对齐,跳到 checkpoint - 部分填写 → 汇报"上次分析做到第 X 步,我从第 Y 步继续",从缺失节开始补做
3. 把上下文读全
- 问题报告全文
AGENTS.md- 报告里提到的相关文件(用 Glob / Grep 找,别只凭 report 里的描述)
easysdd/architecture/DESIGN.md(如果涉及跨模块问题)- 归档检索(按需)——只在问题涉及的模块曾有归档记录时才搜(目录为空或与问题无关就跳过)。统一搜
easysdd/compound/,按需用doc_type过滤:- 一把搜:
python easysdd/tools/search-yaml.py --dir easysdd/compound --query "{issue 关键词}" - 只看技巧:追加
--filter doc_type=trick --filter status=active—— 命中则在分析开头标注引用 - 只看探索:追加
--filter doc_type=explore—— 命中则标注历史探索结论 - 只看经验(pitfall):追加
--filter doc_type=learning --filter track=pitfall—— 命中则标注历史 pitfall
- 一把搜:
分析的五步
每一步都要真正读代码,不要靠推测。
步骤 1:定位问题代码
根据报告里的"涉及模块 / 功能"和"复现步骤",用 Grep / Glob 找相关代码:
- 搜报告里提到的函数名、类名、文件名
- 沿调用链追溯(从用户触发的入口往下找)
- 重点关注:条件分支、边界值处理、状态更新、异步逻辑、数据流转
记下定位到的关键位置:{文件}:{行号} — {说明这里干什么}。
步骤 2:还原失败路径
对照复现步骤,在脑子里(或实际跑一遍)把代码执行路径走一遍:
- 用户触发了什么 → 调了哪个函数 → 数据怎么流 → 哪里分叉走错了
- 描述"正确路径"和"失败路径"的分叉点
- 分叉点 = 根因候选
步骤 3:确认根因
- 单一根因 vs 多个根因:有多个根因就一一列出,说明主次
- 根因分类(帮助后续定位修复范围):
- 逻辑错误:条件判断有误、边界值处理缺失
- 状态污染:某处副作用影响了后续流程
- 数据格式:输入 / 输出格式假设不符合实际
- 并发 / 竞态:异步顺序或共享状态问题
- 配置 / 环境:依赖了某个未稳定的配置项
- 缺少防御:没处理 null / undefined / 空列表等边界
步骤 4:影响面评估
- 影响范围:只影响报告描述的场景,还是会影响更多场景?
- 潜在受害者:哪些其他功能 / 模块可能被同一根因波及?
- 数据完整性:这个 bug 会不会导致数据损坏或状态不一致?
- 严重程度复核:和报告里的 P0/P1/P2/P3 比较,是否需要调整?
为什么要复核严重程度?report 阶段用户给的是基于现象的判断,分析后你看到了影响面——往往会发现问题比看上去严重(一个看似 P2 的小 bug 实际影响了核心数据的完整性)或没那么严重。
步骤 5:修复方案选项
列 2-3 种修复方向,每种说明:
- 做什么:改哪里、怎么改(代码层面描述,不需要写代码)
- 优点:为什么这么改好
- 缺点 / 风险:改这里可能带来什么副作用
- 影响面:改动会触碰哪些文件、会不会影响其他功能
推荐方案:在 2-3 种里挑一种说明推荐理由(通常是:改动范围最小 + 根因最直接 + 副作用最少)。
根因分析模板
分析完写进文件(路径见 easysdd-issue 的"文件放哪儿"节):
---
doc_type: issue-analysis
issue: {issue 目录名}
status: draft
root_cause_type: logic | state-pollution | data-format | concurrency | config | missing-guard
related: [{slug-report.md 相对路径}]
tags: []
---
# {问题简述} 根因分析
## 1. 问题定位
| 关键位置 | 说明 |
|---|---|
| `{文件}:{行号}` | {这里干什么,为什么有问题} |
| `{文件}:{行号}` | ... |
## 2. 失败路径还原
**正常路径**:
{用户做 A → 调用 B → 数据经过 C → 结果 D(符合期望)}
**失败路径**:
{用户做 A → 调用 B → 在 C 处因为 E 走了错误分支 → 结果 F(不符合期望)}
**分叉点**:`{文件}:{行号}` — {为什么这里走错了}
## 3. 根因
**根因类型**:{逻辑错误 / 状态污染 / 数据格式 / 并发竞态 / 配置环境 / 缺少防御}
**根因描述**:
{一段话说清楚为什么会发生这个问题,要能让没看过代码的人理解}
**是否有多个根因**:{是 / 否。如果是,列出并说明主次}
## 4. 影响面
- **影响范围**:{只影响报告场景 / 还会影响 X、Y、Z 场景}
- **潜在受害模块**:{列出可能被波及的其他模块或功能}
- **数据完整性风险**:{有 / 无。有的话说明风险内容}
- **严重程度复核**:{维持 P? / 调整为 P?,理由}
## 5. 修复方案
### 方案 A:{方案名}
- **做什么**:{改哪里、怎么改}
- **优点**:{...}
- **缺点 / 风险**:{...}
- **影响面**:{会动哪些文件,会不会影响其他功能}
### 方案 B:{方案名}
- **做什么**:{...}
- ...
### 推荐方案
**推荐方案 {A / B}**,理由:{改动范围最小 / 根因最直接 / 副作用最少 + 具体说明}
checkpoint:和用户对齐
写完 {slug}-analysis.md 后别直接开始修。做一次对齐:
- 把"根因"和"推荐方案"口头总结给用户(不要让用户去读整份文件——TA 已经在等结论了)
- 问用户:"根因判断是否准确?推荐的修复方案你是否认可,还是想选别的方向?"
- 等用户明确确认方案后才触发阶段 3
退出条件
- YAML frontmatter 存在,
doc_type=issue-analysis、issue跟当前 issue 目录一致 - 根因分析 5 节都填完
- 定位到了具体的代码位置(
{文件}:{行号}粒度) - 失败路径还原清晰
- 影响面评估完成
- 至少列出 2 种修复方案并给出推荐
- 用户明确确认方案:"分析准确,用方案 X 修"
- 用户确认后,frontmatter 的
status已改成confirmed
退出后
告诉用户:"根因分析已就绪,方案已确认。下一步是阶段 3:修复验证。可以触发 easysdd-issue-fix 技能开始修复。"
别自己顺手开始改代码——理由跟其他阶段一样:跨阶段无停顿地往下跑会让用户来不及把关。
容易踩的坑
- 根因写"可能是某处的问题"——必须定位到具体文件:行号
- 没读代码就靠问题描述推断根因——一定要实际 Grep / Read
- 只列一种修复方案——至少给用户两种选择
- 分析完直接开始改代码——必须等用户确认方案
- 影响面写"可能影响其他功能"——要具体说是哪些功能 / 模块
- 严重程度复核总是"维持原级别"——认真看影响面,确实升级的要改