en un clic
verify-and-fix
交付前需验证完成,或修 bug 需修病因不修症状时。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
交付前需验证完成,或修 bug 需修病因不修症状时。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
| name | verify-and-fix |
| description | 交付前需验证完成,或修 bug 需修病因不修症状时。 |
把"声称完成"变成"经验证完成"。核心:代码写完 ≠ 测试过 ≠ 类型对 ≠ 真的没问题——这三个"≠"是大多数返工和线上事故的源头。本 skill 的纪律是:交付前用工具实际跑一遍验证,修 bug 时找根因而非压症状,绝不为"通过"而弱化检查。
灵感来自 multi-agent "loop engineering"(写代码的 agent 与检查的 agent 分离、循环到全绿)。但本 skill 提炼的是纪律本身——无论单 agent 迭代还是多 agent loop,验证-修复的纪律不变。loop 是一种强制实现,纪律才是本质。
不该用:纯探索/原型阶段(本来就不要求正确,验证是负担);明确无失败可能的确定性逻辑(过度验证也是负担)。
与相邻 skill 的衔接:verify-and-fix 在 task-breakdown 的下游——每个任务的"完成定义"就是它的验证目标。task 拆出"做完 X 后能验证 Y",verify-and-fix 负责"实际去验证 Y、不通过就修"。它把 task-breakdown 里的"完成定义"从纸面标准变成实际跑过的证据。
"我看了一遍,应该没问题"——这是最危险的完成声明。代码审查(肉眼看)不能替代运行验证。肉眼能发现风格、明显逻辑错,但发现不了:实际运行时的类型不匹配、边界数据触发的分支、依赖交互、并发时序。
完成的标准必须是实际跑过的证据:
重构场景尤其要防回归:把 for 循环换成 find、换库、提函数、改异步为同步——这类"等价改写"最易悄悄丢失原代码处理的边界(原循环在没找到时可能返回 null/抛业务错,find 改写后这个分支没了)。验证重构时,问自己:原代码处理过哪些情况?新写法每一条都覆盖了吗? 尤其是边界——空集合、找不到、异常输入。重构的验证标准比新写更高:新写只验"能跑",重构还要验"行为没变"。
反例:用户说"我把 for 循环改成 find,应该没问题",你附和"嗯看着对"——但
find可能返回 undefined,.name就抛错。这种 bug 肉眼看不出来,跑一下立刻暴露。
修 bug 最常见的错法:在报错末端兜底,把错误压住,而不查它为什么报错。
Cannot read 'map' of undefined → 加可选链 data?.map(...) 压住。错误消失了,但 data 为什么是 undefined 的病因还在——换个场景又会炸。result is 4, expected 5 → 把断言改成 toBe(4)。测试变绿了,但"为什么是 4 而不是 5"的问题被掩盖。区分"合理兜底"和"掩盖 bug":
user.nickname ?? user.name——昵称本来就可不填。判断尺子:问"这个 undefined/null 在什么情况下出现?"——能说出一个合理的业务场景("用户没填昵称")→ 合理兜底;说不清、或答"反正运行时出现了"→ 是 bug,查源头。
修病因的路径:沿错误向上游追溯——报错点 ← 数据从哪来 ← 谁产生/传递的 ← 什么条件下变成这样。修在最上游的"产生"处,而不是最下游的"消费"处。
断言失败时的灰度——先确认期望值的权威性。测试报"实际 4,期望 5"时,别本能地认定"代码错了、断言对"。先问:期望值 5 从哪来? 是规格文档/业务约定的硬需求 → 代码错了,修代码;还是开发者随手写的猜测("我觉得应该是 5")→ 可能断言本身错了。区分两种"改断言":
判断尺子:改完的断言,描述的是"应该怎样"还是"现在怎样"? 前者(哪怕是改出来的)可能正确;后者(让断言迁就现状)一定错。
这是不可越界的底线。当测试/类型检查挡路时,正确的反应是修代码让它真正通过,错误的是改检查让它放行:
toBe(5) → toBe(4))——测试退化成"描述现状",失去验证意义@ts-ignore / any 压住类型错(除非有明确临时理由 + 留 TODO)try/catch 吞掉异常让流程"通过"|| [] / || {} 给本该有值的东西兜个默认值让它"不报错"为什么这条是红线:弱化检查制造的是欺骗性通过——绿灯看起来像"完成",实际是"绕过了验证"。它比直接失败更危险,因为失败会逼你修,欺骗性通过会让你带着 bug 交付。检查挡路是信号,不是障碍——它在告诉你"这里有真实问题"。
唯一例外:临时调试想跑通流程时可以临时禁用某项检查,但必须留显式标记(TODO + 理由),且不进主分支。
修 bug 时,失败报告(报错、堆栈、行号、复现步骤)是定位根因的唯一线索。别在传递过程中"总结"或"过滤"它:
TypeError: Cannot read 'name' of undefined at user.js:12,调用栈:getProfile←render,复现:用户列表为空时触发"。为什么:根因往往藏在行号、调用栈、触发条件里。"有个 bug"这种总结把这些全丢了,逼修的人从零重新发现。哪怕你觉得某些信息"无关",也原样保留——是否相关由修的人判断,不由你过滤。
在多 agent loop 里这条尤其关键:checker 的失败报告必须原样转发给 builder,编排器不能自作主张总结("checker 说有点问题"会把行号丢了)。单 agent 迭代同理——别把上一轮的报错"消化"成模糊印象,留着原文对照。
修完一个 bug,只跑出问题的那个测试是不够的——你的修复可能让别处悄悄坏了。修复后的验证范围应该是全部相关测试,不是只跑改动点:
为什么:修复本质是改动,改动就有副作用。只验"原本报错的地方不报了"会漏掉"修复让别处报错了"。这就是回归——表面上修好了 A,实际引入了 B。养成习惯:修完默认跑全量相关测试,把"只跑改的那个"当作偷懒的危险信号。
验证范围要匹配改动的影响面,不是无脑跑全量(那是另一种浪费):
判断尺子:这次改动可能波及哪些代码? 影响面 = 验证范围。低估影响面(把共享改动当叶子改)是回归的常见源头;高估影响面(叶子改动跑全量)只是慢,不危险——拿不准时往大了跑。
修了 A 引入 B、修 B 又引入 A——这种循环不罕见。没有刹车的循环会无限转下去,越改越烂。预设停止条件:
刹车不是放弃,是防止把"修不好"变成"越改越糟"。到达刹车条件时,正确动作是退回重新设计或求助,而不是继续在同一处硬磨。
| 问题 | 修法 |
|---|---|
| 没跑就声称完成("看着应该没问题") | 跑测试/类型检查/实际运行,用证据替代肉眼判断 |
| 修症状(末端兜底压住报错) | 向上游追溯根因,在最上游产生处修 |
| 为通过弱化检查(改断言/删测试/any/吞异常) | 红线不可越——修代码真正通过,而非改检查放行 |
| 把失败报告总结成"有个 bug" | 原样保留报错/行号/堆栈/复现步骤 |
| 修复无限循环、越改越乱 | 预设刹车(轮次/重复失败/回归/无进展),到点停并退回 |
| 把合理兜底(可选字段)当 bug 修,或反过来 | 问"空值何时出现"——有合理业务场景=兜底,说不清=bug |
| 重构只验"能跑",不验"行为没变" | 重构要覆盖原代码处理过的所有边界,标准比新写更高 |
| 修复后只跑出问题的测试 | 跑全部相关测试(调用方/共享逻辑/全量),防回归 |
需求模糊、含隐藏假设或 X-Y problem,需先澄清再动手时。
审查代码(自己的或别人的),需有重点、分层次地看时。
Git 改动需编写规范提交信息时。
遇到 bug、报错、崩溃或行为异常,需定位根因时。
设计或改进错误处理与日志时。
在 Lion-Skills 仓库创建或修改 skill 时。