git:20260905.751659e to git:20260905.64eb187

1 added, 1 removed. Audit A to A.

---
name: systematic-debugging
description: 在遇到缺陷、测试失败、构建失败、异常行为或排查卡住时使用。适用于不能靠猜修、需要先定位根因再改代码的场景。
---
# 系统化排查问题
## 目标
先找到根因,再做修复。
避免“猜一个改一个”的随机试错。
## 何时使用
- 测试失败
- 构建失败
- 功能行为异常
- 线上或本地缺陷
- 已经试过几次修复但没解决
## 核心原则
- 先复现,再分析
- 先看证据,再下结论
- 先建立能区分对错的反馈环,再正式修复
- 一次只验证一个假设
- 排障早期可以并行收集互不依赖的证据,但结论必须按证据链收敛
- 修复症状不等于修复根因
- 在改代码前,必须能用一句话说出根因假设
## 基本流程
1. 读清楚报错和上下文
2. 稳定复现问题
3. 建立能稳定复现失败的反馈环:能稳定失败、能复跑、能在修复后变绿;可以是测试、最小复现命令、脚本、页面操作或日志判定
4. 并行收集互不依赖的证据:日志、配置差异、近期变更、网络/环境状态、相关源码路径
5. 建立假设矩阵,按证据强弱排序
6. 用一句话写出当前最高置信假设:`我认为根因是 X,因为证据 Y`
7. 用最小改动或最小观测手段验证该假设
8. 每轮验证后更新假设矩阵;被证伪的方向不要继续加码
9. 只有在根因明确后才正式修复
### 反馈环要求
- 没有反馈环时,只能做读取、复现、加观测或缩小范围;不要直接提交修复
- 反馈环必须足够小,能区分当前假设是否成立,不用一开始就跑全量测试
- 如果问题无法本地复现,要写清替代证据:日志模式、线上状态、CI 失败、用户提供的稳定步骤或最小可观察指标
- 修复后必须用同一个反馈环证明问题消失,再按风险补充更宽的验证
## 常见检查点
- 报错信息、堆栈、日志
- 最近提交或配置变更
- 输入、输出、状态流转
- 环境差异
- 网络路径、端口、DNS、代理、证书、服务发现和防火墙规则
- 是否有现成正常案例可对比
- 是否有最近已知正常版本版本、截图、旧行为或旧产物可当作对照
## 低层基线
系统、工具链、渲染、网络或生成物问题,先测更低一层的事实,再判断上层症状:
- 界面异常先区分 DOM/CSS/渲染层、数据层和状态层
- 网络异常先确认 DNS、代理、证书、端口和服务端响应,再改客户端逻辑
- 编译/工具链异常先确认版本、路径、环境变量和最小命令,再改业务代码
- 生成物异常先确认源文件、生成命令、输出路径和时间戳,再改消费方
## 假设矩阵
排障超过一个明显路径时,维护一个轻量矩阵:
```text
假设 | 证据 | 置信度 | 下一步检查 | 证伪条件
```
- `假设`:具体根因,不写“环境问题”这类空泛词。
- `证据`:已有事实,例如日志、配置差异、命令输出、源码条件。
- `置信度`:高 / 中 / 低。
- `下一步检查`:下一步最小验证动作。
- `证伪条件`:什么结果出现时应放弃该方向。
连续两个假设被证伪后,必须回到矩阵重新排序;不要沿着最熟悉的方向继续猜。
## 可用参考
遇到下面这些问题时,优先参考同目录下的补充文档:
- `root-cause-tracing.md`:适用于错误出现在很深的调用链里,需要一路往上追源头。
- `condition-based-waiting.md`:适用于测试或异步逻辑依赖时序,不能靠 sleep 猜等待时间。
- `defense-in-depth.md`:适用于一个问题可能需要多层保护,避免只修一处留下同类缺口。
## 强化模式
### 重复回归 / 截图对照模式
适用于:
- 用户说“还是不对”“修了但症状没消失”
- 用户给了旧截图、旧版本、旧产物作为参考
- 视觉结果以前是对的,现在坏了
处理方式:
1. 列出所有症状,不只盯住第一条。
2. 明确参考基准:旧截图、旧版本、旧提交、预期状态。
3. 先定义通过或失败检查,再决定怎么修。
4. 同样症状在一次修复后仍存在时,立即停止叠补丁,回到证据重新建模。
### 二分定位模式
适用于用户说“以前是好的”“之前是好的”“某个版本还能用”,或能提供最近已知正常版本。
1. 先保护当前工作区:`git status --short --branch -uall`;有改动时不要在当前检出目录直接二分定位。
2. 先读最近正常版本到当前的相关路径差异;如果范围不大,通常比完整二分定位更快。
3. 必须先定义非交互通过或失败命令;没有可复现检查时,二分定位只会制造噪音。
4. 二分定位得到嫌疑提交后,只读该提交差异,定位引入回归的具体条件。
### 范围扩散检查
适用于修复一类模式问题后,需要确认仓库里是否还有同型缺陷。
1. 提炼缺陷模式:函数、正则、选择器、锁、校验缺口、输入边界。
2. 在仓库中搜索同类形状。
3. 对每个命中项明确写出:同类问题 / 安全例外 / 还需确认。
4. 不要只修用户指出的那一处就宣布结束。
### 运行时证据阶梯
宣布修复前,尽量沿这条链路补齐证据:
1. 源码路径:具体到函数、条件、文件或状态转移
2. 稳定复现:最小复现命令、测试、页面路径或输入
3. 运行时证据:日志、状态、缓存、生成物、外部系统反馈
4. 针对性测试或构建
5. 真正的运行结果确认:尤其是界面、渲染、生成物问题
仅编译通过,不足以证明界面、渲染和产物类问题已修好。
### 定向日志
加日志前先写清楚:这条日志要回答什么问题。
- 第一条日志优先打在执行路径中点,不要直接堆在症状点
- 只记能区分假设的事实:分支、旧值/新值、输入键、错误码、顺序
- 临时日志在结束前移除
- 当假设涉及回调顺序、对象生命周期、异步状态、窗口/导航事件时,日志应作为形成假设的一部分,而不是连续修错后才补
### 配置修改安全线
排障中修改配置、版本、端口、权限或网络参数前:
1. 记录原值和文件路径。
2. 说明该修改要验证哪个假设。
3. 优先做最小临时变更,不混入无关优化。
4. 验证失败立即回滚,不把失败尝试留在最终状态。
## 常见错误
- “先随便改一下试试”
- 一次改很多地方
- 没复现稳定就开始修
- 只看表面症状
- 连续试了多次还不回头重新分析
- 同样症状没消失,还继续沿着旧假设补丁
- 修好一处就假设其他同类位置也没问题
## 输出要求
- 问题现象是什么
- 如何复现
- 当前证据指向什么
- 根因假设是什么
- 假设矩阵如何排序,哪些方向已被证伪
- 验证结果是什么
- 最终修复是否已经验证
- 若做了范围扩散检查,要写清还有无同类命中项
## 关键约束
- 根因没明确前,不要给大幅修复方案
- 连续几次假设都失败时,要停下来重新分析
- 不能把“猜中一次”当成排查方法
- 同样症状在一次修复后仍存在时,必须回到根因分析
- - 连续 3 个假设被证据推翻后,应改为交接式汇报,而不是继续盲试
+ - 连续 3 个假设被证据推翻后,先汇总证据和已排除方向,重新选择诊断方法;有可执行且已获授权的下一步时继续,不因失败次数自动结束任务或转为交接
- 同一数值、阈值、间距或超时被调了 3 次还不对时,停止调参,回到结构约束或不变量