---
name: systematic-debugging
description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes - four-phase framework (root cause investigation, pattern analysis, hypothesis testing, implementation). NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST.
metadata:
  short-description: 系统化调试与根因分析
  keywords:
    - systematic-debugging
    - 调试
    - Bug 修复
    - 根因分析
    - 问题诊断
    - 堆栈追踪
    - 生产环境调试
    - root cause
    - debugging
  category: 调试
  author: Bensz Conan
  platform: Claude Code | OpenAI Codex | ChatGPT
  iron-law: |
    NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
---

# Systematic Debugging - 系统化调试

## BenszAPI 任务工作区

本 Skill 的新任务中间文件统一写入 `./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/{skill名}/input|output|log/`。同一任务复用一个任务根目录；多 Skill 协作才创建 `shared/`。正式交付物不写入该目录，历史隐藏目录只允许显式兼容读取、迁移或清理。

## 与 bensz-collect-bugs 的协作约定

- 因本 skill 设计缺陷导致的 bug，先用 `bensz-collect-bugs` 规范记录到 `~/.bensz-skills/bugs/`，不要直接修改用户本地已安装的 skill 源码；若有 workaround，先记 bug，再继续完成任务。
- 只有用户明确要求“report bensz skills bugs”等公开上报时，才用本地 `gh` 上传新增 bug 到 `huangwb8/bensz-bugs`；不要 pull / clone 整个仓库。

## 铁律

```
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
```

**违反规则的信件就是违反规则的精神。**

**无例外**：
- 不跳过根因调查直接修复
- 不基于猜测进行修复
- 不尝试多个更改同时测试
- 不在不完全理解的情况下修复

---

## 常见合理化

| 借口 | 现实 |
|------|------|
| "快速修复现在，稍后调查" | 永不会有"稍后"。技术债积累 |
| "尝试改变 X，看是否有效" | 猜测不是调试。可能碰巧修复但未理解 |
| "添加多个更改，运行测试" | 无法确定哪个更改有效。浪费调试时间 |
| "可能大概差不多是 X" | 模糊理解导致错误修复 |
| "不完全理解但可能有效" | 理解不完全=修复不完整 |

---

## 红色标志 - 停止并重新开始

- "快速修复现在，稍后调查"
- "尝试改变 X，看是否有效"
- "添加多个更改，运行测试"
- "可能大概差不多是 X，让我修复"
- "不完全理解但可能有效"
- 基于猜测而非证据的修复

**所有这些意味着：停止修复。回到根因调查阶段。**

---

## 四阶段框架

### 阶段 1：根因调查

**任何修复前**：

1. **仔细阅读错误消息**
   - 不要跳过错误或警告
   - 它们通常包含确切解决方案

2. **一致复现**
   - 你能可靠触发吗？

3. **检查最近变更**
   - 什么变更可能导致此问题？

4. **多组件系统收集证据**
   ```bash
   # 对于每个组件边界：
   - 记录进入组件的数据
   - 记录退出组件的数据
   - 验证环境/配置传播
   - 检查每层状态
   运行一次以收集显示何处中断的证据
   然后分析证据以识别失败组件
   然后调查该特定组件
   ```

5. **追踪数据流**
   - 向后追踪到坏值起源

### 阶段 2：模式分析

1. **找到工作示例**
2. **与参考对比**
3. **识别差异**
4. **理解依赖**

### 阶段 3：假设与测试

1. **形成单一假设**："我认为 X 是根本原因，因为 Y"
2. **最小化测试**：进行最小可能更改
3. **验证后再继续**
4. **3+ 次修复失败时：质疑架构**

### 阶段 4：实现

1. **创建失败测试用例**
2. **实施单一修复**：只改验证该假设所需的最小范围
3. **验证修复**：一次只验证一个假设，不把多个修复混在同一次验证里
4. **收敛范围**：避免顺手重构、无关格式化或新增未证明必要的抽象
5. **如果 3+ 次修复失败：质疑架构**

---

## 核心理念

**系统化调试** 不是碰运气，而是方法化地解决问题的科学流程。

```
┌─────────────────────────────────────────────────────────┐
│  收集证据 → 形成假设 → 系统验证 → 定位根因 → 实施修复  │
└─────────────────────────────────────────────────────────┘
```

**核心原则**：
- **基于证据，而非猜测**
- **治疗根本原因，而非症状**
- **一次验证一个假设**
- **记录整个过程**

---

## 何时使用本技能

在以下场景时激活：

- 出现错误、异常、Bug
- 需要分析堆栈追踪（Stack Trace）
- 提到"调试"、"排查问题"、"定位根因"
- 生产环境问题分析
- 跨文件或跨模块的问题追踪
- 间歇性 Bug（时有时无）

---

## 调试工作流程

### 步骤 1：收集证据 📋

**信息收集清单**：

| 证据类型 | 收集方法 | 重要性 |
|---------|---------|--------|
| **完整堆栈追踪** | 复制完整错误信息 | ⭐⭐⭐⭐⭐ |
| **相关日志** | 查看应用日志 | ⭐⭐⭐⭐⭐ |
| **复现步骤** | 记录如何触发问题 | ⭐⭐⭐⭐ |
| **环境信息** | OS、版本、依赖 | ⭐⭐⭐ |
| **代码变更** | 最近的 Git 提交 | ⭐⭐⭐⭐ |
| **用户输入** | 触发问题的数据 | ⭐⭐⭐ |

**堆栈追踪分析示例**：

```python
# 示例错误
Traceback (most recent call last):
  File "app.py", line 45, in process_order
    result = payment_service.charge(amount)
  File "payment.py", line 78, in charge
    return api_client.post("/charge", data)
  File "api.py", line 23, in post
    response = self.session.request(method, url, **kwargs)
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
```

**分析要点**：
1. **从下往上读**：最下面是根本原因
2. **追踪调用链**：app.py → payment.py → api.py
3. **识别错误类型**：SSL 证书验证失败
4. **定位失败点**：api.py 第 23 行

### 步骤 2：形成假设 💡

**假设生成规则**：

1. **基于证据**：不要凭空猜测
2. **优先考虑最近变更**
3. **从简单到复杂排序**
4. **一次只关注一个假设**

**假设模板**：

```
假设：[问题描述] 的原因是 [根本原因]
触发条件：[什么情况下会出现]
验证方法：[如何证明或否定]
```

**假设示例**：

```
假设：SSL 错误的原因是生产环境缺少证书文件
触发条件：部署到生产环境后首次调用 API
验证方法：检查 /etc/ssl/certs/ 目录是否存在证书
```

**常见根因分类**：

| 类别 | 典型原因 | 检查方法 |
|------|---------|---------|
| **配置问题** | 环境变量、配置文件错误 | 检查 .env、config |
| **依赖问题** | 版本冲突、缺失依赖 | 检查 requirements.txt |
| **数据问题** | 空值、格式错误、边界值 | 检查输入数据 |
| **并发问题** | 竞态条件、死锁 | 检查锁、线程安全 |
| **资源问题** | 内存泄漏、连接池耗尽 | 检查资源使用 |
| **逻辑错误** | 边界条件、空值处理 | 代码审查 |

### 步骤 3：系统验证 🔍

**验证原则**：

1. **一次验证一个假设**（控制变量）
2. **设计最小化验证实验**
3. **记录验证过程和结果**
4. **用排除法缩小范围**

**验证方法**：

```python
# 方法 1：添加日志
def process_order(order_id):
    logger.info(f"Processing order: {order_id}")
    order = get_order(order_id)
    logger.debug(f"Order data: {order}")
    # ...

# 方法 2：断点调试
import pdb; pdb.set_trace()

# 方法 3：简化输入
def test():
    # 用最小输入验证
    process_order({"id": 1, "amount": 0})
```

**验证记录模板**：

```markdown
## 假设验证记录

### 假设 1：证书文件缺失
- **验证方法**：检查文件是否存在
- **验证结果**：❌ 文件存在
- **结论**：假设不成立，排除

### 假设 2：证书过期
- **验证方法**：检查证书有效期
- **验证结果**：✅ 证书已于 3 天前过期
- **结论**：假设成立，定位根因
```

### 步骤 4：定位根因 🎯

**区分症状与根因**：

使用**五问法**（5 Whys）深入挖掘：

```
问题：订单处理失败

Why 1: 为什么失败？
→ API 调用返回 500 错误

Why 2: 为什么 API 返回 500？
→ 数据库查询超时

Why 3: 为什么查询超时？
→ 缺少索引导致全表扫描

Why 4: 为什么缺少索引？
→ 新增字段时未同步添加索引

Why 5: 为什么未添加索引？
→ 没有 Code Review 流程

根因：缺少 Code Review 机制（而非"API 返回 500"）
```

**根因特征**：
- ✅ **可操作**：可以采取措施
- ✅ **可预防**：可以防止再次发生
- ✅ **系统级**：不是个人失误

### 步骤 5：实施修复 🔧

**修复原则**：

1. **最小化修复范围**
2. **添加回归测试**
3. **修复后验证**
4. **更新文档**

**修复清单**：

```markdown
## 修复计划

### 代码修复
- [ ] 修改代码：[具体位置]
- [ ] 添加测试：[测试用例]
- [ ] 运行测试确认通过

### 预防措施
- [ ] 添加检查机制
- [ ] 更新文档
- [ ] 团队分享经验

### 验证
- [ ] 本地验证
- [ ] 测试环境验证
- [ ] 生产环境验证
```

---

## 调试技巧库

### 技巧 1：二分法调试

当问题可能出现在多个位置时：

```python
# 在中间点添加日志
def complex_function(data):
    logger.info("Step 1: Start")
    result1 = step1(data)
    logger.info(f"Step 1 result: {result1}")

    logger.info("Step 2: Start")
    result2 = step2(result1)
    logger.info(f"Step 2 result: {result2}")

    logger.info("Step 3: Start")
    result3 = step3(result2)
    logger.info(f"Step 3 result: {result3}")

    return result3
```

### 技巧 2：最小化复现

```python
# 从复杂场景中提取最小复现用例
def test_minimal_reproduction():
    # 不需要完整的订单数据
    order = {"amount": 100}  # 最小输入
    result = process_payment(order)
    assert result.success
```

### 技巧 3：对比法调试

```python
# 对比工作版本和失败版本
def test_working_vs_broken():
    # 工作版本
    result_working = old_api_call(data)

    # 失败版本
    try:
        result_broken = new_api_call(data)
    except Exception as e:
        print(f"Broken: {e}")

    # 对比差异
    compare_results(result_working, result_broken)
```

### 技巧 4：环境隔离

```bash
# 使用 Docker 隔离环境
docker run -it python:3.11 bash

# 或使用虚拟环境
python -m venv debug_env
source debug_env/bin/activate
```

---

## 常见问题模式

### 模式 1：时序问题

**症状**：间歇性失败，时好时坏

**根因**：竞态条件、异步操作未正确等待

**调试方法**：
```python
# 添加重试和延迟
from tenacity import retry, stop_after_attempt, wait_fixed

@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
def flaky_operation():
    # 可能失败的操作
    pass
```

### 模式 2：内存问题

**症状**：性能逐渐下降，最终崩溃

**根因**：内存泄漏

**调试方法**：
```python
import tracemalloc

tracemalloc.start()
# ... 运行代码 ...
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
for stat in top_stats[:10]:
    print(stat)
```

### 模式 3：状态污染

**症状**：测试单独通过，批量运行失败

**根因**：测试间共享状态

**调试方法**：
```python
@pytest.fixture(autouse=True)
def reset_state():
    # 每个测试前重置状态
    reset_database()
    reset_cache()
    yield
    cleanup()
```

---

## 验证清单

修复完成后，检查：

- [ ] 根本原因已识别（非症状）
- [ ] 修复方案最小化
- [ ] 添加回归测试
- [ ] 本地验证通过
- [ ] 文档已更新（如需要）
- [ ] 团队已分享经验
- [ ] 预防措施已实施

---

## 相关参考

- [系统化调试指南](../references/debugging-systematic.md)
- [根因追踪](root-cause-tracing.md)
