mcpField
S
systematic-debugging

systematic-debugging

github.com/sickn33开发48.7k1.6k 次安装今天更新
代码仓库

关于 systematic-debugging

面向开发者和编码 Agent 的调试技能,以分阶段流程取代猜测:先调查根因,再逐一测试假设,最后实施并验证针对性修复。

主要功能

  1. 01四阶段根因调查流程
  2. 02复现故障并收集证据
  3. 03比较正常与异常模式
  4. 04逐一测试单个假设
  5. 05用回归测试验证修复

适用场景

  1. 01调查生产故障和测试失败
  2. 02追踪跨组件故障来源
  3. 03诊断构建与集成问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill systematic-debugging

安装后在 Claude Code 中输入/systematic-debugging确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

condition-based-waiting-example.ts
condition-based-waiting.md
CREATION-LOG.md
defense-in-depth.md
find-polluter.sh
root-cause-tracing.md
test-academic.md
test-pressure-1.md
test-pressure-2.md
test-pressure-3.md

详细介绍

系统化调试

概述

随机的修复会浪费时间并制造新的 Bug。快速补丁会掩盖底层问题。

核心原则: 先调查再猜测,并将经过验证的修复与临时缓解措施区分开来。在事故期间,授权的回滚或遏制措施可以在根因调查继续进行的同时恢复服务。

违反此流程的字面要求,就是违反调试的精神。

铁律

NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST

从可观察到的故障和最小有用的证据检查开始。明确标注任何紧急缓解措施,并为后续的根因调查保留证据。

何时使用

适用于任何技术问题:

  • 测试失败
  • 生产环境中的 Bug
  • 意外行为
  • 性能问题
  • 构建失败
  • 集成问题

尤其在以下情况使用:

  • 时间紧迫(紧急情况会让猜测变得诱人)
  • “就一个快速修复”看起来很明显
  • 你已经尝试过多次修复
  • 之前的修复没有奏效
  • 你并不完全理解该问题

不要跳过,当:

  • 问题看起来很简单(简单的 Bug 也有根因)
  • 你很着急(仓促必然导致返工)
  • 经理要求立刻修好(系统化比乱撞更快)

四个阶段

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

阶段 1:根因调查

在尝试任何修复之前:

  1. 仔细阅读错误信息

    • 不要跳过错误或警告
    • 它们往往包含确切的解决方案
    • 完整阅读堆栈跟踪
    • 记录行号、文件路径、错误代码
  2. 稳定复现

    • 你能可靠地触发它吗?
    • 确切的步骤是什么?
    • 每次都会发生吗?
    • 如果无法复现 → 收集更多数据,不要猜测
  3. 检查最近的变更

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

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

    在提出修复方案之前,添加诊断插桩:

    For EACH component boundary:
      - Record allowed field names, sizes, statuses and correlation IDs
      - Redact secrets and private payloads before logging
      - Verify environment/config propagation
      - Check state at each layer
    
    Run once to gather evidence showing WHERE it breaks
    THEN analyze evidence to identify failing component
    THEN investigate that specific component
    

    示例(多层系统):

    # In each relevant process, report presence only; never dump secret values.
    if [ -n "${IDENTITY:-}" ]; then
      echo 'IDENTITY is set'
    else
      echo 'IDENTITY is absent or empty'
    fi
    
    # Read-only validation of an already-built artifact, when available.
    codesign --verify --verbose=2 "$APP"
    

    解读: 在实际的工作流/构建边界处比较存在性检查。制品验证本身并不能证明正确的签名身份已传播。

  5. 追踪数据流

    当错误位于调用栈深处时:

    请参阅本目录中的 root-cause-tracing.md,了解完整的反向追踪技术。

    快速版本:

    • 错误的值源自哪里?
    • 是什么用错误的值调用了这里?
    • 继续向上追踪,直到找到源头
    • 在源头修复,而不是在症状处修复
阶段 2:模式分析

在修复之前找到模式:

  1. 找到可用的示例

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

    • 如果要实现某个模式,请完整阅读参考实现
    • 不要略读——逐行阅读
    • 在应用之前充分理解该模式
  3. 找出差异

    • 可用的与出问题的之间有什么不同?
    • 列出每一处差异,无论多小
    • 不要假设“那不可能有影响”
  4. 理解依赖关系

    • 它还需要哪些其他组件?
    • 需要哪些设置、配置、环境?
    • 它做了哪些假设?
阶段 3:假设与测试

科学方法:

  1. 提出单一假设

    • 明确说明:“我认为 X 是根本原因,因为 Y”
    • 把它写下来
    • 要具体,不要含糊
  2. 最小化测试

    • 做出尽可能最小的改动来测试假设
    • 一次只改一个变量
    • 不要同时修复多个问题
  3. 继续之前先验证

    • 起作用了吗?是 → 阶段 4
    • 没起作用?提出新的假设
    • 不要在已有改动之上再叠加更多修复
  4. 当你不知道时

    • 说“我不理解 X”
    • 不要假装知道
    • 寻求帮助
    • 做更多研究
阶段 4:实施

修复根本原因,而不是症状:

  1. 创建失败的测试用例

    • 尽可能最简单的复现
    • 如有可能,使用自动化测试
    • 如果没有框架,就写一次性测试脚本
    • 修复之前必须完成
    • 在合适时,使用 test-driven-development 进行聚焦的行为回归
  2. 实施单一修复

    • 解决已识别的根本原因
    • 一次只做一个改动
    • 不要有“顺便改一下”的改进
    • 不要捆绑重构
  3. 验证修复

    • 现在测试通过了吗?
    • 没有破坏其他测试吗?
    • 问题真的解决了吗?
  4. 如果修复不起作用

    • 停止
    • 数一数:你已经尝试了多少次修复?
    • 如果 < 3:回到阶段 1,带着新信息重新分析
    • 如果 ≥ 3:停止并质疑架构(见下方第 5 步)
    • 不要在未讨论架构的情况下尝试第 4 次修复
  5. 如果 3 次以上修复都失败了:质疑架构

    表明架构问题的模式:

    • 每次修复都在不同地方揭示新的共享状态/耦合/问题
    • 修复需要“大规模重构”才能实施
    • 每次修复都会在其他地方制造新症状

    停止并质疑根本假设:

    • 这种模式从根本上成立吗?
    • 我们是不是“仅凭惯性在坚持它”?
    • 我们应该重构架构,还是继续修复症状?

    在尝试更多修复之前,与你的真人搭档讨论

    反复失败是重新评估假设和耦合的证据;它们并不能证明架构是错的。

危险信号 - 停止并遵循流程

如果你发现自己在想:

  • “先快速修一下,之后再调查”
  • “就先改一下 X 看看有没有用”
  • “添加多个改动,然后运行测试”
  • “跳过测试,我会手动验证”
  • “大概就是 X,让我把它修一下”
  • “我没有完全理解,但这可能行得通”
  • “模式说是 X,但我会换个方式调整它”
  • “主要问题如下:[未经调查就列出修复方案]”
  • 在追踪数据流之前就提出解决方案
  • “再试一次修复”(当已经试过 2 次以上时)
  • 每次修复都在不同地方揭示新问题

所有这些都意味着:停止。回到阶段 1。

如果 3 次以上修复都失败了: 质疑架构(见阶段 4.5)

你的真人搭档发出的做错了的信号

留意这些纠偏:

  • “那并没有发生吗?” - 你没有验证就假设了
  • “它会向我们展示……吗?” - 你应该加入证据收集
  • “别猜了” - 你在没有理解的情况下提出修复
  • “深入思考这件事” - 质疑根本假设,而不仅仅是症状
  • “我们卡住了?”(沮丧地) - 你的方法不起作用

当你看到这些时: 停止。回到阶段 1。

常见的合理化借口

借口现实
“问题很简单,不需要流程”简单问题也有根因。对于简单 bug,流程很快。
“紧急情况,没时间走流程”系统化调试比反复猜测和试错更快。
“先试试这个,然后再调查”第一次修复就设定了模式。从一开始就做对。
“等确认修复有效后再写测试”未经测试的修复不会稳固。先测试才能证明它。
“一次做多个修复能节省时间”无法隔离出哪个起了作用。还会引入新 bug。
“参考资料太长,我会照着模式改一改”部分理解必然导致 bug。要完整读完。
“我看到问题了,让我来修”看到症状 ≠ 理解根因。
“再试一次修复”(在 2 次以上失败后)3 次以上失败 = 架构问题。质疑模式,不要再次修复。

快速参考

阶段关键活动成功标准
1. 根因阅读错误、复现、检查变更、收集证据理解 WHAT 和 WHY
2. 模式查找可用示例、比较识别差异
3. 假设形成理论、最小化测试确认或产生新假设
4. 实现创建测试、修复、验证Bug 已解决,测试通过

当流程揭示“没有根因”时

如果系统化调查显示问题确实是环境性的、依赖时序的或外部的:

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

说明剩余的不确定性,以及能够区分环境性故障与实现缺陷的证据。

支持技术

这些技术是系统化调试的一部分,并在此目录中提供:

  • root-cause-tracing.md - 通过调用栈向后追踪 bug,以找到最初的触发点
  • defense-in-depth.md - 找到根因后在多个层添加验证
  • condition-based-waiting.md - 用条件轮询替代任意超时

相关技能:

  • test-driven-development - 聚焦行为的回归
  • 在声称成功之前,使用当前仓库的验证命令

完整示例与预期结果

输入:一次本地构建成功,但在 CI 中失败,因为构建子进程中缺少所需的身份标识。只记录每个边界处是否设置了它,检查环境变量是如何转发的,并只更改一次该传播。重新运行失败的构建,并单独验证产物。预期:子进程收到所需配置,原始失败消失;日志中不包含凭据值。

输入和前置条件

一个可复现的命令或观察到的失败、精确的修订版本/运行时、最近的变更,以及对授权测试环境的访问权限。随附的历史案例说明用于展示该技术;其中报告的计数不是本项目的全新测量值或保证。

限制

  • 临时缓解与根因修复是不同结果;当事件需要立即遏制时,要同时记录两者。
  • 日志可能暴露机密或个人路径。使用允许列表摘要,并在分享前检查捕获的产物。
  • polluter 辅助程序会运行项目的测试命令,并可能执行项目代码;使用隔离的 fixture/checkout,并验证运行器接受文件参数。
  • 等待示例需要领域适配器,无法让所有竞态都变得不可能。复现实际的超时/错误路径。

评论

支持 Markdown