issue-troubleshooting

Installation
SKILL.md

问题排查与修复

概述

随机猜测式修 bug 浪费时间,还会引入新问题。快速补丁掩盖根因,迟早复发。

核心原则:先找到根因,再动手修复。治症不治本就是失败。

本 skill 在经典调试流程基础上,新增修复规模评估环节——当修复工作量较大时, 联动 implementation-planning skill 创建结构化修复计划,避免盲目修改导致混乱。

铁律

没有根因调查,就不允许提修复方案

未完成 Phase 1 之前,不能提出任何修复建议。

适用场景

适用于任何技术问题:

  • 测试失败
  • 生产 bug
  • 异常行为
  • 性能问题
  • 构建失败
  • 集成问题

尤其适用于:

  • 有时间压力时(紧急情况更易猜测)
  • "看上去很简单,改一下就行"时
  • 已经试了多次修复都没用时
  • 上一次修复没生效时
  • 没有完全理解问题时

不应跳过的场景:

  • 问题看起来简单(简单 bug 也有根因)
  • 着急(匆忙等于返工)
  • 领导催着修复(系统排查比瞎改更快)

五阶段流程

每个阶段必须完成后才能进入下一阶段。

Phase 1:根因调查

在提出任何修复之前:

  1. 仔细阅读错误信息

    • 不要跳过任何错误或警告
    • 错误信息往往包含精确线索
    • 完整阅读堆栈跟踪
    • 记录行号、文件路径、错误码
  2. 稳定复现

    • 能可靠触发吗?
    • 精确的复现步骤是什么?
    • 每次都出现吗?
    • 无法复现 → 收集更多数据,不要猜
  3. 检查近期变更

    • 什么变更可能导致了这个问题?
    • Git diff、近期提交
    • 新依赖、配置变更
    • 环境差异
  4. 多组件系统收集证据

    当系统有多个组件(CI → 构建 → 签名,API → 服务 → 数据库):

    在提出修复之前,添加诊断埋点:

    对每个组件边界:
      - 记录进入组件的数据
      - 记录离开组件的数据
      - 验证环境/配置传播
      - 检查每层状态
    
    运行一次收集证据,定位故障出现在哪一层
    再针对该组件深入调查
    
  5. 追踪数据流

    当错误在调用栈深处:

    参见 references/root-cause-tracing.md 的完整回溯追踪技术。

    简版:

    • 错误值从哪来?
    • 谁传入了错误值?
    • 持续向上追溯直到源头
    • 在源头修复,不在表象处修复

    不确定是哪个测试造成污染时: 使用 scripts/find-polluter.sh 二分定位:

    ./scripts/find-polluter.sh '.git' 'src/**/*.test.ts'
    

Phase 2:模式分析

修复前先找模式:

  1. 找正常工作的参照

    • 在同一代码库找到类似的正常工作代码
    • 什么能正常工作?跟出问题的有什么相似?
  2. 对比参考实现

    • 如果是在实现某个模式,完整阅读参考实现
    • 不要略读——逐行阅读
    • 完全理解模式后再应用
  3. 识别差异

    • 正常代码和异常代码之间有什么不同?
    • 列出每个差异,不管多小
    • 不要假定"这不重要"
  4. 理解依赖

    • 需要哪些其他组件?
    • 需要什么设置、配置、环境?
    • 有哪些隐含假设?

Phase 3:假设验证

科学方法:

  1. 提出单一假设

    • 明确陈述:"我认为 X 是根因,因为 Y"
    • 写下来
    • 要具体,不要含糊
  2. 最小化测试

    • 做最小改动来验证假设
    • 一次只改一个变量
    • 不要同时修多个东西
  3. 验证后再继续

    • 验证通过?→ 进入 Phase 4 规模评估
    • 没通过?→ 提出新假设
    • 不要在失败的假设上叠加新修改
  4. 不懂就说不懂

    • 说"我不理解 X"
    • 不要装懂
    • 寻求帮助
    • 继续研究

Phase 4:修复规模评估

在进入实施之前,评估修复的规模和复杂度。这是本 skill 区别于普通调试流程的关键步骤。

规模评估标准

对已确认的根因,评估以下维度:

维度 小修 大修
涉及文件数 ≤ 3 个文件 > 3 个文件
涉及模块 单一模块 跨模块/跨层
预估工时 < 4 小时 ≥ 4 小时
变更性质 逻辑修正/参数调整 架构调整/接口变更/新增组件
测试影响 修改少量测试 需要新增测试套件/重构测试结构
前后端 仅一端 前后端都需改动

决策规则

小修(满足以下全部条件)→ 直接进入 Phase 5:

  • 修改 ≤ 3 个文件
  • 不跨模块
  • 预估 < 4 小时
  • 不涉及接口变更

大修(满足以下任一条件)→ 联动 implementation-planning:

  • 修改 > 3 个文件
  • 跨模块或跨层
  • 预估 ≥ 4 小时
  • 涉及接口变更、架构调整
  • 前后端都需改动
  • Phase 3 中已失败 3+ 次假设(说明问题可能在架构层面)

联动 implementation-planning 的流程

当判断为大修时:

  1. 整理修复方案概要

    • 根因说明(来自 Phase 1-3 的结论)
    • 修复范围(涉及的模块/层/文件)
    • 修复策略(来自 Phase 2 的模式分析)
    • 修复约束(不能破坏的现有行为、兼容性要求)
  2. 检查技术方案是否已存在

    • 如果 workplace/1.X/tech-design/ 下有相关技术方案 → 直接引用
    • 如果没有 → 先输出一份简要修复方案(作为技术方案的替代),再进入实施计划
  3. 调用 implementation-planning skill

    • 将修复方案概要作为输入
    • 生成的计划中每个模块标注 [BUGFIX] 前缀,区分于正常需求开发
    • 计划中增加"回归验证"模块作为最后一个模块
  4. 修复计划模板补充

    联动生成的计划中,每个模块详情需额外包含:

    **关联根因**:[本模块修复的根因部分]
    **风险点**:[本模块修改可能影响的现有行为]
    **回退方案**:[如果修复引入新问题如何回退]
    

    计划末尾增加回归验证模块:

    ### M{N}: 回归验证
    
    **目标**:确认修复未引入新问题
    ****:跨层
    **前置依赖**:所有修复模块
    
    **子步骤**1. 运行全量测试套件
    2. 验证原 bug 场景已修复
    3. 检查关联功能的回归
    
    **验收标准**- 全量测试 PASS
    - 原 bug 复现步骤不再触发
    - 关联功能无回归
    
  5. 向用户说明

    • 告知用户为什么判定为大修
    • 展示修复方案概要
    • 提交计划供用户确认后再执行

Phase 5:修复实施

根据 Phase 4 的决策,走两条路线:

路线 A:小修直接实施

  1. 创建失败测试用例

    • 最简复现
    • 尽量自动化测试
    • 无框架时用一次性脚本
    • 修复前必须有测试
  2. 实施单一修复

    • 针对已确认的根因
    • 一次改一处
    • 不做"顺手优化"
    • 不捆绑重构
  3. 验证修复

    • 测试通过了?
    • 没有破坏其他测试?
    • 问题确实解决了?
  4. 修复未生效

    • 停下来
    • 计数:已经试了几次修复?
    • < 3 次 → 回到 Phase 1,用新信息重新分析
    • ≥ 3 次 → 进入架构质疑(步骤 5)
    • 不要在 3 次失败后继续试第 4 次
  5. 3+ 次修复失败:质疑架构

    架构问题的信号:

    • 每次修复都在不同位置暴露新的共享状态/耦合
    • 修复需要"大规模重构"才能实施
    • 每次修好在 A 处,B 处又出问题

    停下来质疑根本问题:

    • 这个模式本身是否合理?
    • 是不是在靠惯性坚持?
    • 应该重构架构还是继续修补?

    在尝试更多修复前,与用户讨论。

    这不是假设失败——这是架构选错了。

    → 此时应联动 implementation-planning,将架构重构作为正式计划推进。

路线 B:大修按计划执行

implementation-planning 生成的修复计划执行:

  1. 读取计划中的执行索引,找到第一个"待执行"模块
  2. 按模块详情实施
  3. 完成后更新状态为"完成"
  4. 继续下一个模块
  5. 最后执行回归验证模块

红灯信号——停下来遵循流程

当你发现自己在想:

  • "先快速修一下,回头再查"
  • "改一下 X 试试看"
  • "把几个改动一起提交"
  • "跳过测试,我手动验证"
  • "大概是 X 的问题,我先改了"
  • "不完全理解但这样可能行"
  • "参考文档太长,我按自己的方式来"
  • 还没追踪数据流就提出解决方案
  • "再试一次修复"(已经失败 2+ 次)
  • 每次修复都在不同位置暴露新问题

以上所有都意味着:停下来,回到 Phase 1。

3+ 次修复失败:质疑架构(见 Phase 5 路线 A 步骤 5)

来自用户的纠偏信号

注意这些提示:

  • "是这样吗?" → 你假设了但没验证
  • "能不能看到……?" → 应该先加证据收集
  • "别猜了" → 你在没有理解的情况下提出修复
  • "好好想想" → 质疑根本问题,不是表象
  • "是不是卡住了?" → 你的方法不奏效

看到这些信号时:停下来,回到 Phase 1。

常见借口

借口 事实
"问题很简单,不需要流程" 简单问题也有根因。流程对简单 bug 更快。
"紧急,没时间走流程" 系统排查比瞎猜快。
"先试试这个,不行再查" 第一次修复定基调。从头就做对。
"先改了确认有效再补测试" 没测试的修复靠不住。测试先证明问题存在。
"几个改动一起省时间" 无法隔离哪个有效。还会引入新 bug。
"参考太长,我按自己理解来" 一知半解必定出 bug。完整阅读。
"看到问题了,我来改" 看到症状 ≠ 理解根因。
"再试一次修复"(失败 2+ 次后) 3+ 次失败 = 架构问题。质疑模式,不要继续试。
"大修就直接动手改吧" 大修没有计划必乱。用 implementation-planning 管住范围。

快速参考

阶段 关键活动 成功标准
1. 根因调查 读错误、复现、查变更、收证据 理解"是什么"和"为什么"
2. 模式分析 找参照、对比差异 识别关键差异
3. 假设验证 提出假设、最小测试 假设确认或提出新假设
4. 规模评估 评估修复范围和复杂度 判定小修直接修 / 大修走计划
5. 修复实施 小修:测试→修复→验证 / 大修:按计划执行 bug 解决,测试通过

当流程揭示"找不到根因"

如果系统调查后发现问题是环境、时序或外部因素导致的:

  1. 你已经完成了流程
  2. 记录调查了什么
  3. 实现适当的处理(重试、超时、错误提示)
  4. 添加监控/日志供未来调查

但注意: 95% 的"找不到根因"其实是调查不够深入。

辅助技术

以下技术是本 skill 的一部分,位于 references/ 目录:

  • root-cause-tracing.md - 沿调用栈回溯追踪 bug 到原始触发点(配套脚本 scripts/find-polluter.sh
  • defense-in-depth.md - 找到根因后在多个层添加验证
  • condition-based-waiting.md - 用条件轮询替代任意超时(配套实现见 scripts/condition-based-waiting-example.ts

关联 skill

  • implementation-planning - 修复规模大时,创建结构化修复计划
  • test-driven-development - 创建失败测试用例(Phase 5 步骤 1)
  • verification-before-completion - 验证修复生效后再宣布完成
Related skills
Installs
4
First Seen
10 days ago