关于 pasteurize
pasteurize 是用于排查难复现软件故障的结构化调试技能。它要求先建立并验证复现循环,再提出排序假设,并指导埋点、回归测试、修复与清理。
主要功能
- 01建立可重复的故障复现循环
- 02多次运行确认预期故障
- 03排列可测试的假设
- 04指导定向埋点与修复
- 05扫描临时调试标记
适用场景
- 01排查不稳定或时序敏感的故障
- 02修改生产代码前追查回归问题
- 03通过回归测试和原复现循环验证修复
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ paulnsorensen/ easy-cheese --skill pasteurize安装后在 Claude Code 中输入/pasteurize确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
wedge.tomlreferences/commands.mdfeedback-loops.md详细介绍
/pasteurize
遇到棘手的 Bug 时,使用此流程。
纪律
**规则:**先建立可靠的反馈闭环,再提出假设。
遇到以下任何警示信号时,都要停下:
- 在闭环还不能复现故障之前就指出原因。
- 把无关故障当作复现结果。
- 因为真实接缝难以处理,就在模拟接缝处添加测试。
- 针对同一组假设尝试修复第四次。
- 没有进行会话标签全面检查,就报告工作树干净。
| 自我辩解 | 回应 |
|---|---|
| “原因很明显。” | 先建立闭环。明显的原因跑一次就能确认。 |
| “编写闭环太慢了。” | 即使闭环很慢,也比错误修复强。 |
| “任何故障都能证明 Bug 存在。” | 确认退出代码或输出是否符合预期。 |
| “模拟接缝已经足够接近。” | 记录缺失的接缝,并转交给 Mold。 |
| “再试一次就能成功。” | 先写一份新的假设列表。 |
探索代码时,遵循 code-intelligence-routing.md。
使用 artifact-path specs 解析规格存储位置。
阅读解析出的目录中有关失败接缝的备注。
阅读 harness-portability.md,了解如何使用可移植工具。
优先使用随附的辅助工具或仓库内的辅助工具,而不是 ${CLAUDE_SKILL_DIR}。
将 ${CLAUDE_SKILL_DIR} 视为可选的宿主回退路径。
将交接区块作为可移植契约。
请记住,斜杠命令是宿主环境的呈现形式,而非控制模型。
输入
<input> 是报告的症状。
接受 Bug 报告、堆栈跟踪、失败测试输出或制品路径。
接受来自 Affinage、Cheese 或 Cook 的调查请求。
调查请求使用以下字段:
| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
source | string | 是 | 发起请求的 skill,例如 affinage。 |
source_ref | string | 否 | 拉取请求评论或发现项标识符。 |
symptom | string | 是 | 用一句话描述报告的故障。 |
expect_exit | integer | 否 | 表示故障的退出代码。 |
expect_output | string | 否 | 故障输出的正则表达式。 |
mode | string | 否 | investigate 或 fix。默认为 fix。 |
接受以下标志:
--auto无需回答两个问题即可运行各阶段。--open-pr通过 Cook 到达 Plate。--hard通过 Cook 到达最终的 Hard-cheese 门禁。
将 --open-pr 和 --hard 传递给每条 /cook 和 /mold 命令。
不要丢弃调用方提供的标志。
Cheese 可以提供 handoff_context.wiki_hits。
每条命中都包含 page、line 和 why 字段。
在第 1 阶段之前阅读每条命中。
指出任何会改变假设排序的命中。
mode: investigate 请求在第 2 阶段后停止。
向来源 skill 返回 reproduced、not-reproduced 或 inconclusive。
调查请求不得启动第 4 阶段。
第 1 阶段:建立反馈闭环
在诊断 Bug 之前,先建立快速且可靠的通过/失败反馈闭环。 此反馈闭环会控制后续所有阶段。
阅读 references/feedback-loops.md,了解按优先顺序排列的闭环选项。
选择能够触及失败接缝的第一个选项。
继续之前,改进闭环。
- 减少设置步骤和无关初始化。
- 检查确切症状。
- 控制时间、随机值、文件和网络访问。
非确定性 Bug
将复现率提高到 50% 以上。 重复触发条件。 增加压力。 缩小时间窗口。 增加可控延迟。
无法建立可用循环
无法建立可用循环时,请停止。
列出你尝试过的每种方法。
请求访问复现环境。
或者,请求获取捕获的产物,或请求允许临时进行生产环境监测。
编写一个 status: needs-context: <the access you need> 交接标记。
协调器提供访问权限后,会重试本次运行。
没有循环时,不要提出假设。
进入第 2 阶段前,请确认以下条件:
- 每次运行循环都会得到相同结果。
- 对于不稳定的循环,复现 bug 的概率超过 50%。
- 一条命令即可运行循环,无需人工操作。
- 循环会检查报告中提到的确切症状。
- 循环在 30 秒内完成。
尽量将循环控制在 5 秒内完成。
第 2 阶段:复现 bug
运行循环 5 次。
python3 skills/pasteurize/scripts/pasteurize.pyz repro-rerun \
--cmd "<repro-command>" --runs 5 \
--expect-output "<expected failure text>" --threshold 0.5 --timeout 30
始终注明预期的故障模式。
对于输出已知的故障,使用 --expect-output。
对于退出代码已知的故障,使用 --expect-exit。
确认结果包含 reproduced: true。
对于确定性 bug,确认 matches 等于 runs。
查看 results 列表,确认每次匹配的运行。
如果运行 5 次仍未复现不稳定的 bug,请增大 --runs 的值。
在循环复现预期故障之前,不要继续。
不要将无关故障视为复现结果。
症状关卡
提出假设前,先对症状进行分类。
- 如果堆栈跟踪清晰且循环可靠,请继续使用当前模型层级。
- 如果涉及竞态、跨模块故障、性能回归或 Heisenbug,请升级模型层级。
使用 harness 命令升级模型。
对于 Claude,使用 /model opus。
然后使用 /effort。
对于 Codex 或 OMP,使用对应的命名命令。
对于其他宿主,使用通用模型升级方式。
第 3 阶段:提出假设
测试任何假设前,先写出 3 至 5 个按优先级排序的假设。 为每个假设说明一个可测试的预测。 无法说明预测的假设应予以舍弃。
使用以下格式:
如果
<X>导致了 bug,那么<changing Y>会消除它,或者<changing Z>会使情况恶化。
通过 handoff-gate.md 展示按优先级排序的列表。
领域知识可以改变排序。
如果用户无法联系,或使用了 --auto,请按当前排序继续。
第 4 阶段:添加检测
将每项探针对应到第 3 阶段的一个预测。 一次只更改一个变量。
按以下顺序使用工具:
- 如果环境支持,请使用调试器或 REPL。
- 在能够区分不同假设的边界处添加有针对性的日志。
- 不要记录所有数据后再进行搜索。
为本次调查选择一个会话标签,例如 a4f2。
每条临时日志前都加上确切的标记 [DEBUG-a4f2]。
在交接标记中记录会话标签。
使用会话标签查找清理过程中需要移除的每条临时日志。
对于性能回归,在更改代码前测量基线。 使用计时 harness、性能分析器或查询计划。 然后对故障区间进行二分查找。
阶段 5:修复 bug
在修复前添加回归测试。 仅当存在正确的测试接缝时才添加测试。
正确的测试接缝会在 bug 实际发生的调用点触发真实 bug。 它使用真实的数据路径和故障模式。 浅层或模拟的测试接缝会带来虚假的信心。
将缺少测试接缝视为架构问题。
在交接 slug 中记录此问题。
写入适用的提前停止状态。
设置 next: mold。
不要在错误的接缝处添加测试。
存在正确的接缝时,完成以下步骤:
- 将最小复现转换为该接缝处的失败测试。
- 运行测试并观察失败。
- 应用能够修复该失败的最小生产代码改动。
- 运行测试并观察成功。
- 运行原始的阶段 1 循环,确认症状已消失。
在下次尝试前撤销未成功的修复。 三次修复尝试均未成功后停止。 返回阶段 3。 编写新的假设排序列表。 没有新假设时,不要进行第四次尝试。
发现新假设时,从阶段 4 重新开始。
否则,写入修复尝试已耗尽状态。
然后设置 next: mold。
将更广泛的改动留给 /cook。
在交接 slug 中记录这些改动。
阶段 6:清理工作树
编写交接 slug 前,完成此清单:
- 运行原始循环,确认 bug 已消失。
- 运行回归测试并确认成功。
- 不存在正确的测试接缝时,记录缺少测试接缝的问题。
- 移除所有
[DEBUG-...]插桩。 - 删除临时测试工具和原型。
- 在 slug 中记录任何保留的调试文件。
- 在 slug 中记录已确认的假设。
使用你的会话标签运行插桩扫描:
python3 skills/pasteurize/scripts/pasteurize.pyz debug-tag-sweep \
--session-tag a4f2 --changed-only --root .
--session-tag 与确切标记 [DEBUG-a4f2] 匹配。
--changed-only 会扫描此工作树中改动过的文件。
扫描会排除 .cheese/、缓存和运行日志等工具输出。
扫描会输出一个包含 files 和 total 的 JSON 对象,并在完成时以状态码 0 退出。
total 为 0 表示扫描未发现标记。
total 非零表示扫描发现了 files 所列的标记。
继续前移除每个列出的标记。
非零退出状态表示输入错误;其 stderr 行是包含 error 和 exit_code 的 JSON。
不要使用范围较广的 --tags 扫描来确认工作树干净。
确定哪些因素可以防止此 bug。 在 slug 中记录必要的架构工作。 应用修复后再提出此建议。
将完成的 slug 交给 /cook <slug> --auto。
Cook 会检查 diff 并运行 cook (⇄ press) -> age -> cure。
Pasteurize 不会提交改动或创建拉取请求。
扇出规模
/pasteurize 当前不会启动任何 Agent。
size_pasteurize_fanout() 在 src/easy_cheese/shared/fanout/pasteurize_route.py 中定义了未来的策略。
该策略会在从最后一个已知正常版本到 HEAD 的可疑范围内,按降序读取 review_surface。
证据评分越低,Agent 数量越多,因为这代表更大的搜索空间。
| Bug 类型 | 范围 | 复现 | Agent 数量 |
|---|---|---|---|
| 回归 | 紧凑,评分 < 250 | 确定性 | 1 |
| 回归 | 紧凑,评分 < 250 | 非确定性 | 2 |
| 回归 | 广泛,评分 > 250 | 确定性 | 2 |
| 回归 | 广泛,评分 > 250 | 非确定性 | 3 |
| 回归 | 无评分 | 确定性 | 3 |
| 回归 | 无评分 | 非确定性 | 5 |
| 竞态、海森堡 bug 或性能回归 | 任意 | 任意 | 3 |
| 冷启动 bug | 无评分 | 确定性 | 3 |
| 冷启动 bug | 无评分 | 非确定性 | 5 |
评分 250 定义了紧凑范围。
这些常量由审查者根据经验设定。运行数据尚未对其进行测量。 审查阈值基于 30 次仓库提交。 这些常量没有运行历史。 保留可调整的命名常量。 有真实运行数据后再审查它们。
仅使用 bundle 的主机可以通过以下命令调用该策略:
python3 skills/pasteurize/scripts/pasteurize.pyz pasteurize-route <request.json>
该命令读取 JSON 并写入 JSON。
它遵循 age-route bundle 约定。
首选工具
| 需求 | 首选工具 | 后备方案 |
|---|---|---|
| 代码搜索与影响分析 | 语义调用方和依赖项搜索 | 限定范围的文本搜索,并提示精确度有限 |
| 读取代码 | 从写入后端进行最新的限定范围读取 | 使用稳定行锚点进行限定范围读取 |
| 插桩编辑 | 可安全处理过期内容的锚定编辑 | 使用 LSP 或快照编辑,并检测过期写入 |
| GitHub 上下文 | gh | 本地 Git 历史或用户提供的链接 |
| 外部检查 | /briesearch | 明确标注的假设 |
可选工具不可用时,仍应继续诊断。
输出
返回一份简短报告,包含以下内容:
- 具名原因及其置信度。
- 循环命令和观察到的结果。
- 考虑过的假设及已确认的假设。
- 回归测试路径。
- 更改的生产代码行。
- 插桩和临时文件清理状态。
- 下一条命令
/cook <slug> --auto。
置信度使用 <certain>、<speculating> 或 <don't know>。
交接 slug
将交接 slug 写入 .cheese/pasteurize/<slug>.md。
使用以下最简格式:
status: <canonical status field>
next: cook | mold | done
artifact: <path-to-richer-report-if-any>
<one-line orientation: what pasteurize confirmed>
cause: <one-sentence named cause>
loop: <command or repro path>
session_tag: <the Phase 4 session tag, or "none">
seam: <regression-test path:line, or "none — architectural follow-up">
fix: <production diff footprint, e.g. "src/foo.ts:42">
follow_up: <architectural follow-up note, or "none">
将方向说明放在第 4 行。
解析器会在方向说明之前读取 status、next 和 artifact。
它不会读取前言中的其他键值行。
在空一行后,将所有诊断字段放入正文。
将更详尽的报告放在 artifact 中,而非诊断内容中。
遵循交接约定。
使用以下状态:
| 状态 | 处理方式 | 用途 |
|---|---|---|
ok | 继续 | 测试、复现和清理检查均成功。 |
ok-with-concerns: <reason> | 继续 | 诊断已完成,但工作需要 Mold。 |
needs-context: <reason> | 重试 | 本次运行需要复现权限或已捕获的产物。 |
halt: <reason> | 停止 | 本次运行无法继续,且没有后续路线。 |
编排器会忽略 halt slug 中的 next:。
不要在 halt slug 中指定路线。
标准链路设置 next: cook。
诊断需要架构规范时设置 next: mold。
外部原因无需更改仓库时设置 next: done。
交接
流程: cheese -> pasteurize -> cook --auto (⇄ press) -> age -> cure -> plate
写好报告和 slug 后,通过 handoff-gate.md 提供以下选项:
- 验证并继续:
/cook <slug> --auto。 - 验证但不启动自动链路:
/cook <slug>。 - 指定架构工作:
/mold <slug>。 - 停止: 将修复留在工作树中。
status: ok 时,推荐选择第一个选项。
用户未选择前,不要启动任何选项。
在 --auto 模式下,跳过此问题。
自动模式
--auto 会跳过 Phase 3 的排序问题。
也会跳过 Phase 6 的交接问题。
清理后启动 /cook <slug> --auto。
不会跳过 Phase 4 或 Phase 5。
提前停止条件
出现以下任一条件时停止:
- Phase 1 无法得出可用的循环。
- 两轮 Phase 3 排除了所有假设。
- Phase 5 找不到合适的回归测试切入点。
- 最小修复导致 pasteurize 范围外的不相关测试失败。
- 连续三次修复均未成功,且所有假设均已排除。
缺少合适的测试切入点时,写入 status: ok-with-concerns: no correct regression-test seam。
修复尝试耗尽时,写入 status: ok-with-concerns: fix attempts exhausted — architectural re-examination needed。
这两种情况都设置 next: mold。
缺少复现权限时,写入 status: needs-context: <the access you need>。
始终写入 slug 并展示报告。
不要用猜测代替证据。
规则
- 不要跳过第 1 阶段。
- 没有复现循环时,不要提出假设。
- 在第 5 阶段,仅修改回归测试和最少量的生产代码。
- 交付前移除所有
[DEBUG-...]标签。 - 不要声称 Pasteurize 已发布此项更改。
- 使用以下完成声明:“原因已明确,回归测试通过,修复已写入代码库,已准备好交接”。
- 在 slug 中记录架构缺口。
参考资料
- 生成捆绑包命令:
references/commands.md。