| name | devflow-fix |
| description | 在处理缺陷、回归、线上问题或紧急修复(DTS/hotfix)时使用:需要复现问题、定位根因、界定最小修复范围时。不用于新功能开发或主动重构。 |
DevFlow 缺陷修复
总览
修缺陷最大的失败模式不是修不好,而是修了症状:没复现就开改、把"不再报错"当"修好了"、顺手把周围看不顺眼的代码一起动了。纪律一句话:
先复现,再归因,后修复;没有失败的测试就没有修复。
产出按问题严重度伸缩:简单缺陷把三段记录(复现/根因/修复边界)写进组件根下 features/DTS<id>-<slug>/fix.md(或团队覆盖路径)即可;根因涉及设计缺陷或行为变更时,回到完整的 spec/design 流程。
工作流
1. 复现
- 用最小步骤稳定复现,记录:触发输入、环境(版本/平台/配置)、预期 vs 实际、证据(日志/core/trace)。
- 复现不了就不要修。 flaky 的问题先想办法提高复现率(压力、注入延迟、缩小区间),仍不可复现 → 记录已排除的假设,交回报告人补信息,不上"盲修补丁"。
2. 根因分析
- 从现象向后追因果链,每一步要有证据(日志、代码路径、git 历史、二分),直到回答「为什么会发生」而不是「在哪发生」。连续追问"为什么"直到再往下是设计决策或外部事实为止。
- 区分三层并全部写下来:直接原因(哪行代码错了)、根本原因(为什么会写错/漏掉——契约不清?边界没定义?测试缺口?)、波及范围(同样的模式还出现在哪里)。
- 被排除的假设记录排除证据——这是防止下一个人重走弯路的最廉价文档。
- 改一行试试看 → 不行再改一行——这是猜,不是归因。两次"试试看"不中就必须停下来回到证据。
3. 界定修复边界
明确写下:最小安全修复范围(哪些文件/函数)、显式不修什么(周边坏味道、同类风险点登记不动手)、回退策略。然后分流:
| 根因性质 | 路径 |
|---|
| 实现错误(逻辑/边界/资源),契约本身正确 | 直接进入步骤 4 |
| 行为/契约需要变更(错误码、接口语义、阈值) | 这是变更不是修复 → 走 devflow-specify(modify 条目 + 基线) |
| 设计缺陷(边界划错、并发模型错) | 回 devflow-design 修订后再实现 |
| 波及范围里发现同类隐患 | 登记为独立工作项,不在本次顺手修 |
4. TDD 修复
- 先写复现缺陷的失败测试(RED):把复现步骤翻译成自动化用例,确认它因为这个缺陷而失败。这个测试就是回归屏障。
- 最小修复让它转绿(GREEN);完整套件确认无回归;必要的清理留在 REFACTOR(纪律同
devflow-tdd)。
- 根因是"测试缺口放过了它" → 补的不只是这一个用例:检查同一缺口下还有哪些边界没有测试。
5. 收尾
fix.md 补全四问:根因是什么、为什么测试没拦住、修复改了什么、同类风险登记在哪。代码与测试按 devflow-review 的 code/test rubric 评审;评审闭环后经 devflow-ship 做 DoD 核验与关闭(DoD 对缺陷工作项的裁剪规则见其 definition-of-done)。
风险信号
- 没有复现记录就出现了修复 diff
- 根因写的是「空指针访问」这种"在哪发生"(直接原因),没有"为什么会发生"
- 修复 diff 里混着重命名、格式化、顺手清理
- 修复后没有新增任何测试("改完手动验了")
- 同一个函数第二次因同类原因被修(第一次的根因分析是假的)
- 用重试/延时/放宽阈值让问题"不再出现"而不解释机理
自检清单
支撑参考
| 文件 | 用途 |
|---|
references/fix-template.md | fix.md 模板(复现/根因/修复边界三段) |