# Diagnose

> 针对严重错误和性能回归的严格诊断循环。重现 → 最小化 → 假设 → 检测 → 修复 → 回归测试。当用户说"诊断这个"/"调试这个"、报告错误、说某物损坏/抛出异常/失败，或描述性能回归时使用。

- Skill: `karasukaigan/diagnose` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add karasukaigan/diagnose`
- Raw SKILL.md: https://api.skillmd.com/api/skills/karasukaigan/diagnose/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: karasukaigan (https://skillmd.com/u/karasukaigan)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/karasukaigan/diagnose

---


# 诊断

针对严重错误的规范。仅在明确合理的情况下跳过阶段。

在探索代码库时，使用项目的领域词汇表来获得相关模块的清晰心理模型，并检查你正在接触的区域中的 ADR。

## 第一阶段 — 构建反馈循环

**这就是技能所在。** 其他一切都是机械性的。如果你有一个快速、确定性、代理可运行的错误通过/失败信号，你就会找到原因——二分法、假设测试和检测都只是消耗该信号。如果你没有这样的信号，再多的盯着代码看也救不了你。

在这里投入不成比例的努力。**要积极主动。要有创造性。拒绝放弃。**

### 构建方法——大致按此顺序尝试

1. **失败的测试**在任何能够触及错误的接缝处——单元测试、集成测试、端到端测试。
2. **Curl / HTTP 脚本**针对正在运行的开发服务器。
3. **CLI 调用**带有固定输入，将标准输出与已知良好的快照进行差异比较。
4. **无头浏览器脚本**（Playwright / Puppeteer）——驱动 UI，对 DOM/控制台/网络进行断言。
5. **重放捕获的跟踪。** 将真实的网络请求/负载/事件日志保存到磁盘；孤立地通过代码路径重放它。
6. **一次性 harness。** 启动系统的最小_subset_（一个服务，模拟依赖项），通过单个函数调用练习错误代码路径。
7. **属性/fuzz 循环。** 如果错误是"有时输出错误"，运行 1000 个随机输入并查找失败模式。
8. **二分法 harness。** 如果错误出现在两个已知状态之间（提交、数据集、版本），自动化"在状态 X 启动，检查，重复"，以便你可以 `git bisect run` 它。
9. **差异循环。** 通过旧版本与新版本（或两个配置）运行相同的输入并差异输出。
10. **HITL bash 脚本。** 最后的手段。如果必须有人点击，使用 `scripts/hitl-loop.template.sh` 驱动_他们_，以便循环仍然结构化。捕获的输出反馈给你。

构建正确的反馈循环，错误就已经 90% 修复了。

### 迭代循环本身

将循环视为产品。一旦你有了_一个_循环，问：

- 我能让它更快吗？（缓存设置、跳过不相关的初始化、缩小测试范围。）
- 我能让信号更清晰吗？（断言特定症状，而不是"没有崩溃"。）
- 我能让它更确定吗？（固定时间、种子 RNG、隔离文件系统、冻结网络。）

一个 30 秒的不稳定循环 barely 比没有循环好。一个 2 秒的确定性循环是调试超能力。

### 非确定性错误

目标不是干净的重现，而是**更高的重现率**。将触发器循环 100 次，并行化，添加压力，缩小时间窗口，注入睡眠。50% 的抖动错误是可调试的；1% 则不可——不断提高比率直到它可调试。

### 当你真的无法构建循环时

停止并明确说明。列出你尝试过的内容。向用户请求：(a) 访问重现它的任何环境，(b) 捕获的工件（HAR 文件、日志转储、核心转储、带时间戳的屏幕录制），或 (c) 添加临时生产检测的权限。在没有循环的情况下**不要**继续进行假设。

在你相信有一个循环之前，不要进入第二阶段。

## 第二阶段 — 重现

运行循环。观察错误出现。

确认：

- [ ] 循环产生**用户**描述的失败模式——而不是恰好 nearby 的不同失败。错误的错误 = 错误的修复。
- [ ] 失败在多次运行中是可重现的（或者，对于非确定性错误，以足够高的比率可重现以进行调试）。
- [ ] 你已经捕获了确切的 symptom（错误消息、错误输出、缓慢计时），以便后续阶段可以验证修复是否真正解决了它。

在你重现错误之前不要继续。

## 第三阶段 — 假设

在测试任何假设之前生成**3-5 个排名假设**。单假设生成会锚定在第一个看似合理的想法上。

每个假设必须是**可证伪的**：陈述它做出的预测。

> 格式："如果 <X> 是原因，那么 <改变 Y> 将使错误消失 / <改变 Z> 将使它更糟。"

如果你不能陈述预测，该假设就是一种感觉——丢弃或 sharpen 它。

**在测试之前向用户显示排名列表。** 他们通常拥有可以立即重新排名的领域知识（"我们刚刚部署了对 #3 的更改"），或者知道他们已经排除的假设。便宜的检查点，大大的时间节省者。不要阻塞——如果用户不在，继续你的排名。

## 第四阶段 — 检测

每个探测必须映射到第三阶段的特定预测。**一次改变一个变量。**

工具偏好：

1. **调试器/REPL 检查**如果环境支持。一个断点胜过十个日志。
2. **目标日志**在区分假设的边界处。
3. 永远不要"记录所有内容并 grep"。

**用唯一前缀标记每个调试日志**，例如 `[DEBUG-a4f2]`。最后的清理变成单个 grep。未标记的日志存活；标记的日志死亡。

**性能分支。** 对于性能回归，日志通常是错误的。相反：建立基线测量（计时 harness、`performance.now()`、分析器、查询计划），然后二分。先测量，后修复。

## 第五阶段 — 修复 + 回归测试

在修复**之前**编写回归测试——但仅当有**正确的接缝**时。

正确的接缝是测试在调用站点发生时练习**真实错误模式**的地方。如果唯一可用的接缝太浅（当错误需要多个调用者时的单调用者测试，无法复制触发错误的链的单元测试），那里的回归测试会给出虚假的信心。

**如果不存在正确的接缝，这本身就是发现。** 注意它。代码库架构正在阻止错误被锁定。将此标记为下一阶段。

如果存在正确的接缝：

1. 将最小化的重现转换为该接缝处的失败测试。
2. 观察它失败。
3. 应用修复。
4. 观察它通过。
5. 针对原始（未最小化）场景重新运行第一阶段反馈循环。

## 第六阶段 — 清理 + 事后分析

在声明完成之前必需：

- [ ] 原始重现不再重现（重新运行第一阶段循环）
- [ ] 回归测试通过（或记录接缝的缺失）
- [ ] 所有 `[DEBUG-...]` 检测已删除（`grep` 前缀）
- [ ] 一次性原型已删除（或移动到清晰标记的调试位置）
- [ ] 结果正确的假设在提交/PR 消息中陈述——以便下一个调试者学习

**然后问：什么可以防止这个错误？** 如果答案涉及架构变更（没有好的测试接缝、纠缠的调用者、隐藏的耦合），将 specifics 移交给 `/improve-codebase-architecture` 技能。在修复到位**之后**提出建议，而不是之前——你现在拥有的信息比开始时更多。
