git:20260919.361331b to git:20260919.7add278

40 added, 173 removed. Audit A to A.

---
name: systematic-debugging
- description: 在遇到缺陷、测试失败、构建失败、异常行为或排查卡住时使用。适用于不能靠猜修、需要先定位根因再改代码的场景。
+ 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. **排序假设**:维护轻量矩阵:
- ### 影响面与关键安全事实
+ `假设 | 支持证据 | 反证 | 置信度 | 下一步最小检查`
- 对可能影响调用方、配置、协议、资源状态或外部系统的变更:
+ 5. **验证一个假设**:用最小观测或可逆改动获取能证实或证伪的结果,不同时改变多个变量。
+ 6. **更新模型**:记录被排除方向;同一症状未消失时停止叠补丁,回到矩阵重新排序。
+ 7. **修复与回归**:根因明确且用户授权修复后,做最小修改;先用原反馈环证明问题消失,再按风险扩大验证。
- 1. 找出一个最能决定安全性的事实,例如“该路径只处理已失效资源”或“重试会收敛到同一个终态”。
- 2. 沿调用链、配置、序列化格式、feature flag 和下游消费者检查这个事实;不要只依赖 grep 命中或局部代码直觉。
- 3. 用真实代码、最小脚本或针对性测试运行一次能推翻该事实的检查,并记录输入、输出和环境。
- 4. 不能运行时保留为未证明假设,说明缺少的运行面和风险;不要用完整编译或静态阅读替代运行时证据。
+ 在改代码前,应能用一句话表达当前假设:`我认为根因是 X,因为证据 Y;结果 Z 会证伪它。`
- 对命令、控制器、迁移、队列和其他会写状态的流程,额外检查重复执行、上次运行中途崩溃、重启和重试是否都能收敛到正确终态。若结果依赖上次留下的临时状态,优先增加恢复或对账逻辑,而不是继续叠加保护分支。
+ ## 没有稳定复现时
- ### 定向日志
+ 只能做读取、加观测和缩小范围,不把猜测提交成修复。记录可替代证据,例如 CI 失败、生产日志、用户的稳定步骤、状态差异或最小监控指标,并说明它比本地复现弱在哪里。
- 加日志前先写清楚:这条日志要回答什么问题。
+ 运行一次后通过不能自动判定 flaky。至少需要近期重复运行、通过对照和能解释失败的基础设施或时序证据。
- - 第一条日志优先打在执行路径中点,不要直接堆在症状点
- - 只记能区分假设的事实:分支、旧值/新值、输入键、错误码、顺序
- - 临时日志在结束前移除
- - 当假设涉及回调顺序、对象生命周期、异步状态、窗口/导航事件时,日志应作为形成假设的一部分,而不是连续修错后才补
+ ## 参考路由
- ### 配置修改安全线
+ 只在命中对应问题时读取:
- 排障中修改配置、版本、端口、权限或网络参数前:
+ - [root-cause-tracing.md](root-cause-tracing.md):错误出现在深层调用链,需要追踪原始输入或触发点。
+ - [condition-based-waiting.md](condition-based-waiting.md):异步或测试依赖时序,需要用条件轮询替代固定 `sleep`。
+ - [defense-in-depth.md](defense-in-depth.md):根因修复后仍需要在多个边界阻止无效状态传播。
+ - [references/advanced-modes.md](references/advanced-modes.md):回归对照、二分定位、同型缺陷搜索、运行时证据和配置诊断。
- 1. 记录原值和文件路径。
- 2. 说明该修改要验证哪个假设。
- 3. 优先做最小临时变更,不混入无关优化。
- 4. 验证失败立即回滚,不把失败尝试留在最终状态。
+ ## 安全边界
- ## 常见错误
+ - 修改配置、版本、端口、权限或网络参数前,记录原值、目标文件和要验证的假设;失败后恢复本轮临时变化。
+ - 生产和共享环境先做只读检查;修复、重启、删除、回滚和权限操作需要明确目标与授权。
+ - 临时日志只记录能区分假设的事实,不输出凭据或敏感数据,并在任务结束前移除不需要的观测代码。
+ - 保护用户工作区中的无关改动,不用破坏性 Git 命令清理环境。
+ - 编译或静态检查通过不能证明界面、网络、生成物、状态机或生产行为已经恢复。
- - “先随便改一下试试”
- - 一次改很多地方
- - 没复现稳定就开始修
- - 只看表面症状
- - 连续试了多次还不回头重新分析
- - 同样症状没消失,还继续沿着旧假设补丁
- - 修好一处就假设其他同类位置也没问题
+ ## 停止与重置
- ## 输出要求
+ - 连续两个假设被证伪后,重新排序矩阵,不沿熟悉方向继续加码。
+ - 连续三个假设被证据推翻后,汇总现象、证据和已排除方向,重新选择诊断方法;有已授权的有效检查时继续,不因计数自动交接。
+ - 同一阈值、超时、间距或数值调整三次仍不对时,停止调参,检查结构约束和不变量。
+ - 缺少完成诊断所必需的访问、日志或复现条件时,报告具体缺口和能继续的最小输入。
- - 问题现象是什么
- - 如何复现
- - 当前证据指向什么
- - 根因假设是什么
- - 假设矩阵如何排序,哪些方向已被证伪
- - 验证结果是什么
- - 最终修复是否已经验证
- - 若做了范围扩散检查,要写清还有无同类命中项
+ ## 输出契约
- ## 关键约束
+ 报告:
- - 根因没明确前,不要给大幅修复方案
- - 连续几次假设都失败时,要停下来重新分析
- - 不能把“猜中一次”当成排查方法
- - 同样症状在一次修复后仍存在时,必须回到根因分析
- - 连续 3 个假设被证据推翻后,先汇总证据和已排除方向,重新选择诊断方法;有可执行且已获授权的下一步时继续,不因失败次数自动结束任务或转为交接
- - 同一数值、阈值、间距或超时被调了 3 次还不对时,停止调参,回到结构约束或不变量
+ - 现象、范围和复现/替代证据;
+ - 当前最高置信假设及其反证条件;
+ - 已排除方向和关键命令/观察;
+ - 根因结论及证据强度,或为什么仍不能确定;
+ - 若已修复:实际改动、原反馈环结果、更宽验证和残余风险;
+ - 若只诊断:不修改文件,并给出下一步最小检查。