debug
系统化排错:以运行时证据走"复现 → 假设 → 验证 → 定位 → 修复 → 回归"闭环,排查报错、测试失败、行为异常。触发:"排查这个 bug"、"debug 一下"、"为什么会报错"、"定位一下问题"、"这个测试为什么挂了",或被 api-testing / e2e-testing / demo-verify 转交定位根因。
SKILL.mdskills/debug/SKILL.md
GitHubDebug(系统化排错)
AI 说明
目的:面对 Bug、报错、测试失败或行为异常时,用运行时证据而非静态猜测收敛根因——每个结论都要有可复现的证据支撑,避免"看代码猜出来的修复"。
功能:执行"信息收集 → 最小复现 → 证据采集 → 假设-验证循环 → 根因定位 → 最小修复 → 回归验证"的排错闭环;支持插桩取证、二分缩小范围;定位后可接力 bug-impact-analysis 对修复做影响质检。
使用场景:用户报告 Bug/报错/异常行为需要定位原因时;测试失败需要排查时;"改了之后行为不对"需要找出引入点时;被 api-testing / e2e-testing / demo-verify 转交定位失败根因时。
核心原则
- 证据优先于猜测:不凭代码阅读下定论,关键结论必须有运行时证据(日志、堆栈、变量值、测试结果)支撑
- 先复现再排查:能稳定复现是排错的起点,无法复现时先想办法复现,而不是盲改
- 一次一个假设:每轮只验证一个假设,避免多变量同时改动导致证据失效
- 二分收敛:范围大时用二分法缩小(git bisect / 逐段注释 / 缩小输入),不做地毯式排查
- 最小修复:只修根因,不顺手重构;修复后必须用复现用例回归验证
- 插桩必清理:临时日志/断言用于取证,定位完成后全部移除
- 经验复用:排查前先查已沉淀的解决方案与专家资产,避免重复踩坑
- 衔接影响分析:根因系统性/跨模块、或存在多个候选修复方案时,修复前先交 bug-impact-analysis 评估影响面;修复完成后(涉及公共函数/多调用方/核心路径)默认接力质检。详见「与 bug-impact-analysis 的分工与互引」
执行流程
Step 0:信息收集
- 现象:报错信息、堆栈、异常行为的具体表现(原文优先,不转述)
- 复现路径:用户提供的复现步骤/失败的测试用例/触发条件
- 最近变更:
git log --oneline -10、git diff,异常是否与近期改动时间吻合 - 环境因素:运行环境、依赖版本、配置差异(本地好的线上坏 → 优先查环境差异)
- 索引定位(仓库有
.fe-index/时最省的一步):use_skill("index-lookup")—— 读.fe-index/INDEX.md判该查哪端 → 后端查tables.md(表 → 模块)、modules/*.md(被依赖 + 事件/命令耦合);前端查apis/*.md(接口 → 页面)。拿到候选文件清单作为排查域,再进 Step 1/2;无索引 / 未命中 / 过期 → 跳过,不阻塞 - 经验查询(可选,失败则跳过):
- 调用 use_skill("expert-solution-workflow") 查询相关经验、解决方案或记忆(如
.solutions/debugging/的现成解法、相关模块专家资产的"已知坑") - 错误类问题可调用
use_skill("ki-memory-lookup")的错误库策略,直接贴报错原文/整段堆栈作 query 检索(语义匹配,路径/版本号/行号变体也能命中,这是.solutions/的 INDEX.md 关键词匹配做不到的)。命中即得根因/解法摘要,但解法是历史沉淀,须按记录里的「验证方式」确认问题真的解决后再复用;未命中/ki 不可用则静默跳过
- 调用 use_skill("expert-solution-workflow") 查询相关经验、解决方案或记忆(如
- 强关联关系查询(可选,失败则跳过):定位到可疑模块后,调用
use_skill("ki-memory-lookup")检索该模块的强关联关系(跨模块契约/业务耦合),辅助判断根因是否位于跨模块耦合处(如数据源/消费端契约、共享结构),扩大排查视野至相关模块
Step 1:构造最小复现
- 优先用最小可复现用例:剥离无关代码/数据,保留能触发问题的最小组合
- 有失败测试 → 直接以该测试为复现载体
- 无测试 → 写一个临时复现脚本(放临时目录或标记清理)
无法复现时:
- 罗列复现依赖的变量(数据、时序、并发、环境),逐个对齐
- 仍无法复现 → 不盲改,输出"排查所需信息清单"请用户补充(如线上日志、真实数据样本)
Step 2:证据采集
按成本从低到高采集:
| 手段 | 说明 |
|---|---|
| 读现有日志/堆栈 | 定位异常抛出点与调用路径 |
| 跑相关测试 | 确认问题边界(哪些场景挂、哪些不挂) |
| 插桩 | 在可疑路径加临时日志/断言,统一带 DEBUG-TRACE 标记便于清理 |
| 调试执行 | 用脚本/REPL 单独驱动可疑函数,观察真实输入输出 |
Step 3:假设-验证循环
证据 → 假设清单(按可能性排序)→ 取最可能的一个 → 设计最小验证 → 运行
↑ ↓
└────────── 证伪:记录并划掉,取下一个假设 ←──────── 证实:进入 Step 4
- 每个假设写成可证伪的形式:"如果是 X 导致的,那么做 Y 应该观察到 Z"
- 验证结果与预期不符 → 该假设被证伪,不允许在证据不符时强行解释
- 假设全部证伪 → 回到 Step 2 补充证据,或用二分法重新划定范围:
- 版本维度:
git bisect定位引入提交 - 代码维度:逐段禁用/短路可疑逻辑
- 数据维度:折半缩小触发输入
- 版本维度:
- 运行时证据枯竭时静态补位:若既无法构造复现、假设又全部证伪,调用
use_skill("bug-impact-analysis")借其调用链/数据流静态分析圈定可疑范围,再回到本 skill 验证。静态补位只用于缩小范围,根因结论仍需运行时证据
Step 4:根因定位
区分三层,与 bug-impact-analysis 的根因链格式对齐:
## 🔍 排查结论
**现象**:[外在表现]
**证据链**:[证据1] → [证据2] → [证据3](每条注明来源:日志/测试/插桩输出)
**直接原因**:[哪行代码的什么行为]
**根本原因**:[为什么会写成这样:设计遗漏/边界未考虑/依赖变化/环境差异]
**引入点**(如适用):[commit/变更]
根因树(🕸 文字树,与上面结论配套输出;不替代证据链):
{现象:报错 / 异常行为原文摘要}
▼
{直接原因:哪行代码的什么行为}(证据:{日志 / 测试 / 插桩输出})
▼
{根本原因 ← 根因}({设计遗漏 / 边界未考虑 / 依赖变化 / 环境差异})
├─ {触发条件 1}({值 / 状态})
└─ {触发条件 2}({值 / 状态})
▼
{引入点:commit / 变更(如适用)}
假设多次转向时,排查路径也用同款树:{H1(证伪:证据)} → {H2(证伪:证据)} → {H3 ← 证实}。
最小语法(跨 skill 统一,4 条):① │+▼ 串联、├─ └─ 分支;② 节点挂数字 / 状态,关键节点打标记(← 根因 / ← 待验证);③ 并行标"(取 max)"、串行标"(串行相加)";④ 只画结构类信息,清单仍用表格;节点 ≤15、层级 ≤4。
修复前的转交判定(条件触发,基于 Step 4 根因结论):
| 判定 | 条件 | 动作 |
|---|---|---|
| 需修复前评估 | 根因为系统性缺陷/跨模块耦合,或存在多个候选修复方案,或修复涉及公共函数/多调用方/核心路径 | 先调用 use_skill("bug-impact-analysis"),用其 Step 2(方案评估)与 Step 3(影响面清单)确定方案与修复边界,再进入 Step 5 |
| 可直接修复 | 单点疏忽、方案唯一、影响面封闭在单个函数内 | 直接进入 Step 5;修复后在 Step 6 按需选 1 质检 |
更深层修复的采纳:若 BIA 判定当前修复「治标不治本」并给出更根本的修复思路,该方案超出本 skill 的「最小修复」原则——是否采纳先经用户确认,再决定是否实施,不自行扩大修复范围。
Step 5:最小修复与回归验证
- 基于根因给出修复方案(含备选时说明取舍),实施最小修复
- 回归验证(必须全过才算修复完成):
- 复现用例:从"失败"变为"通过"
- 相关既有测试:无新增失败
- 清理:移除所有
DEBUG-TRACE插桩与临时复现脚本(有价值的复现用例建议转正为正式测试)
Step 5.5:沉淀错误库(仅独立使用时)
回归验证通过后,若本次错误属非平凡(满足任一:解决过程 ≥3 步 / 需查文档试错 / 有复现性 / 含非显而易见的技巧 / 涉及工具框架的坑),调用 use_skill("ki-memory-write") 的错误库策略写一条原子(内容:报错原文片段 / 现象 / 根因 / 解法 / 验证方式 / 关联方案)。
- 仅独立使用时写:本 skill 被
api-testing/e2e-testing/demo-verify转调时,由调用方决定是否写入,不在被转调路径上无条件写(对齐「需求管理集成」既有约定) - 查重前置,命中则更新不新建:写入前先查重,命中已有条目则更新(补报错变体 / 更优解法),避免同一报错换路径/版本号即被当作"新错误"造成重复爆炸
- 不复制
.solutions/方案正文:错误库只存路标 + 指向.solutions/{分类}/{ID}/,完整方案仍留在.solutions/,二者不互相复制 - 不写平凡错误:拼写错误、路径写错、语法错误、一次性环境偶发问题不写
- 降级:ki 不可用则跳过写错误库,不阻塞主流程(与其余经验沉淀约定一致)
Step 6:后续步骤
排查与修复已完成,请选择后续步骤:
1. 📊 发起 bug-impact-analysis — 对本次修复做影响面与回归风险质检
2. 💾 沉淀解决方案 — 调用 solution-capture 将本次排查记录到 .solutions/debugging/(同时写入 ki 错误库)
3. 无需后续
请选择 [1 / 2 / 3]
- 修复涉及公共函数/多调用方/核心路径时,默认推荐选 1(若 Step 4 已做过修复前评估,此处只关注实际改动落地后的影响面,不重复评估方案;若 Step 5 回归验证出现既有测试由绿转红,说明修复引入回归,同样走选 1 定位影响面)
- 被其他 skill 调用(子 agent / 无人值守)时跳过询问,直接返回排查结论与修复结果
与 bug-impact-analysis 的分工与互引(SSOT)
| debug(本 skill) | bug-impact-analysis | |
|---|---|---|
| 回答的问题 | 为什么坏了、怎么修 | 修得对不对症、会不会弄坏别的 |
| 证据来源 | 运行时证据(复现/插桩/测试) | 静态推理(调用链/条件路径/数据流) |
| 是否改代码 | 会——目标就是修好 | 不改,仅出质检报告 |
双向接力全景:
只有现象、无修复代码 → debug 复现取证 → 根因定位(Step 4)
├─ 根因系统性 / 跨模块 / 多候选方案 / 涉及公共函数 → 【修复前】
│ bug-impact-analysis 评估方案与影响面 → 回到 debug Step 5 实施最小修复
└─ 单点问题、方案唯一、影响面封闭 → 直接进入 Step 5
↓
【修复后】bug-impact-analysis 质检(涉及公共函数/多调用方/核心路径时默认必做)
↓
影响项待验证 / 同类风险待确认 → 回到 debug 复现取证
↓
(可选)challenger 质疑质检报告
转交 bug-impact-analysis 的时机(debug → BIA):
| 时机 | 触发条件 | 动作 |
|---|---|---|
| 修复前·方案评估 | 根因为系统性缺陷/跨模块耦合,或存在多个候选修复方案 | 借其 Step 2 对比方案、Step 3 给影响面清单,再回来实施,避免方案选错返工 |
| 修复前·面界定 | 修复涉及公共函数/多调用方/核心路径 | 先拿影响面清单作为最小修复的边界约束 |
| 修复后·质检 | 同上(默认必做);其余按需 | Step 6 选 1 接力 |
| 排查受阻·静态补位 | 假设全部证伪且无法构造复现,运行时证据枯竭 | 借其调用链/数据流静态分析圈定范围,再回到本 skill 验证 |
| 回归新失败 | Step 5 回归验证出现既有测试由绿转红 | 修复引入回归,先由 BIA 定位影响面再修 |
被 bug-impact-analysis 调用时(BIA → debug):BIA 缺运行时证据时转来取证(复现/插桩/跑测试),取证完成把 Step 4 结论回传 BIA,由它继续影响分析——本 skill 不产出影响分析报告,也不替 BIA 下影响结论。
避免重复分析:本 skill Step 4 的根因结论可直接作为 BIA Step 1 的输入;BIA 的影响面清单可直接作为本 skill Step 5 的修复边界。两侧各有一次分析,不重复做对方那份。
互转终止规则(防乒乓):同一问题在本 skill 与 BIA 之间往返各限一次——本 skill → BIA → 本 skill 后即停止互转,输出「阻塞清单」(已排除的假设、缺失的信息、需要用户补充的内容)请用户补充信息或人工介入,禁止无限来回。测试类 skill 转交同理:本 skill 判定为「断言口径错」交回调用方后,若再次失败,需用户确认是修断言还是修代码,不再自动转回。
被测试类 skill 调用时(SSOT)
api-testing / e2e-testing / demo-verify 判定「失败」但不负责定位「为什么失败」,根因不明时会转来本 skill。被转交时:
收到的输入:失败断言(实际 vs 期望)、复现命令/脚本、相关日志或响应原文、已排除的可能性。
本 skill 的职责边界:
| 做 | 不做 |
|---|---|
| 用运行时证据定位失败根因 | 不重跑对方的全量测试/旅程/原型验证(只跑最小复现) |
| 给最小修复并回归验证 | 不改测试断言口径——若判定是断言写错而非代码 Bug,交回调用方修正断言 |
| 区分「被测代码 Bug」与「环境/数据/时序问题」 | 不越权判定业务方案是否可行(demo-verify 的「方案不可行」结论由其自己下) |
回传:Step 4 根因结论 + 修复结果回传给调用方,由它更新测试报告/验证报告后继续。若根因属调用方配置问题(编排写错、断言口径错、原型实现 Bug),明确说明并交回,不代替修改测试资产。
行为边界
- 插桩不留痕:所有临时日志/断言/复现脚本在结束前必须清理,
DEBUG-TRACE标记全局搜索确认为零 - 只修根因:不在排错过程中顺手重构、改风格、扩功能
- 不掩盖问题:禁止用 try/except 吞异常、放宽断言、跳过测试等方式"让报错消失"来代替修复
- 证据可追溯:排查结论中每个判断注明证据来源;无证据支撑的推断标注
[推测] - 危险操作先确认:删除数据、修改配置/环境、回滚提交等不可逆操作必须先征得用户同意;普通插桩与修复无需逐步确认
需求管理集成
当项目配置了 .requirements/config 且关联了 REQ 时,独立使用的排查完成后(被其他 skill 调用时跳过,由调用方统一集成):
- 将 Step 4 排查结论 + Step 5 修复摘要写入需求目录
review/debug-report.md - 注册文档关联:
req update {REQ-NNN} \
--docs add review/debug-report.md,review --changelog "完成 Bug 排查与修复"
- 错误处理:需求 ID 不存在或未关联 REQ → 跳过集成,仅展示排查结论;文件锁超时 → 重试 1 次,仍失败则告知用户