agentsclimarketplace

Verify and fix

Skill Lion-1209/Lion-Skills/skills/verify-and-fix

面向开发者的 Claude Code skills 套件 | A developer-focused Claude Code skills suite

Install
npx -y skills add Lion-1209/Lion-Skills --skill verify-and-fix

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

交付前需验证完成,或修 bug 需修病因不修症状时。

SKILL.md

10.2 KB, as published. Nobody here has run it

Verify and Fix

概述

把"声称完成"变成"经验证完成"。核心:代码写完 ≠ 测试过 ≠ 类型对 ≠ 真的没问题——这三个"≠"是大多数返工和线上事故的源头。本 skill 的纪律是:交付前用工具实际跑一遍验证,修 bug 时找根因而非压症状,绝不为"通过"而弱化检查。

灵感来自 multi-agent "loop engineering"(写代码的 agent 与检查的 agent 分离、循环到全绿)。但本 skill 提炼的是纪律本身——无论单 agent 迭代还是多 agent loop,验证-修复的纪律不变。loop 是一种强制实现,纪律才是本质。

何时使用

  • 刚写完代码,准备声称"完成"/"修好了"
  • 修 bug,决定怎么修
  • 测试/类型检查报错,要处理
  • 来回改同一处反复出问题(怀疑在原地打转)

不该用:纯探索/原型阶段(本来就不要求正确,验证是负担);明确无失败可能的确定性逻辑(过度验证也是负担)。

与相邻 skill 的衔接verify-and-fix 在 task-breakdown 的下游——每个任务的"完成定义"就是它的验证目标。task 拆出"做完 X 后能验证 Y",verify-and-fix 负责"实际去验证 Y、不通过就修"。它把 task-breakdown 里的"完成定义"从纸面标准变成实际跑过的证据。

核心内容

第一原则:未经运行的代码不算完成

"我看了一遍,应该没问题"——这是最危险的完成声明。代码审查(肉眼看)不能替代运行验证。肉眼能发现风格、明显逻辑错,但发现不了:实际运行时的类型不匹配、边界数据触发的分支、依赖交互、并发时序。

完成的标准必须是实际跑过的证据

  • 有测试 → 跑测试,全绿才算过
  • 有类型系统(TS/带 type hint 的 Python/Rust)→ 跑类型检查
  • 能跑 → 实际跑一遍目标场景
  • 三者都要,不是任选其一(测试过不代表类型对,类型对不代表运行时分支都对)

重构场景尤其要防回归:把 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——昵称本来就可不填。
  • 掩盖 bug:值本不该为空却空了——说明上游有 bug(数据源问题、初始化遗漏、路径没覆盖)。这时兜底只是把火盖住,火还在烧。

判断尺子:问"这个 undefined/null 在什么情况下出现?"——能说出一个合理的业务场景("用户没填昵称")→ 合理兜底;说不清、或答"反正运行时出现了"→ 是 bug,查源头。

修病因的路径:沿错误向上游追溯——报错点 ← 数据从哪来 ← 谁产生/传递的 ← 什么条件下变成这样。修在最上游的"产生"处,而不是最下游的"消费"处。

断言失败时的灰度——先确认期望值的权威性。测试报"实际 4,期望 5"时,别本能地认定"代码错了、断言对"。先问:期望值 5 从哪来? 是规格文档/业务约定的硬需求 → 代码错了,修代码;还是开发者随手写的猜测("我觉得应该是 5")→ 可能断言本身错了。区分两种"改断言":

  • 错的改断言:期望值有权威来源(规格/约定),为了通过把它改成实际值——这是弱化检查。
  • 对的改断言:发现期望值本身就是错的(规格已改、当初写错了),改成正确的期望值——这是修正错误期望,不是放水。

判断尺子:改完的断言,描述的是"应该怎样"还是"现在怎样"? 前者(哪怕是改出来的)可能正确;后者(让断言迁就现状)一定错。

红线:绝不为"通过"弱化检查

这是不可越界的底线。当测试/类型检查挡路时,正确的反应是修代码让它真正通过,错误的是改检查让它放行

  • ❌ 把断言从期望值改成实际值(toBe(5)toBe(4))——测试退化成"描述现状",失去验证意义
  • ❌ 删掉报错的测试
  • @ts-ignore / any 压住类型错(除非有明确临时理由 + 留 TODO)
  • ❌ 用 try/catch 吞掉异常让流程"通过"
  • || [] / || {} 给本该有值的东西兜个默认值让它"不报错"

为什么这条是红线:弱化检查制造的是欺骗性通过——绿灯看起来像"完成",实际是"绕过了验证"。它比直接失败更危险,因为失败会逼你修,欺骗性通过会让你带着 bug 交付。检查挡路是信号,不是障碍——它在告诉你"这里有真实问题"。

唯一例外:临时调试想跑通流程时可以临时禁用某项检查,但必须留显式标记(TODO + 理由),且不进主分支。

保留原始失败信息

修 bug 时,失败报告(报错、堆栈、行号、复现步骤)是定位根因的唯一线索。别在传递过程中"总结"或"过滤"它

  • 差:"测试挂了,有个 bug"——builder/你自己无从下手,只能瞎猜。
  • 好:完整保留报错原文、行号、堆栈、触发场景。"TypeError: Cannot read 'name' of undefined at user.js:12,调用栈:getProfile←render,复现:用户列表为空时触发"。

为什么:根因往往藏在行号、调用栈、触发条件里。"有个 bug"这种总结把这些全丢了,逼修的人从零重新发现。哪怕你觉得某些信息"无关",也原样保留——是否相关由修的人判断,不由你过滤。

在多 agent loop 里这条尤其关键:checker 的失败报告必须原样转发给 builder,编排器不能自作主张总结("checker 说有点问题"会把行号丢了)。单 agent 迭代同理——别把上一轮的报错"消化"成模糊印象,留着原文对照。

修复后防回归:跑全部相关,不只跑改的

修完一个 bug,只跑出问题的那个测试是不够的——你的修复可能让别处悄悄坏了。修复后的验证范围应该是全部相关测试,不是只跑改动点:

  • 改了函数 X → 跑所有调用 X 的测试,不只跑 X 自己的
  • 改了共享逻辑 → 跑全量测试
  • 改了配置/类型定义 → 跑受影响的所有模块

为什么:修复本质是改动,改动就有副作用。只验"原本报错的地方不报了"会漏掉"修复让别处报错了"。这就是回归——表面上修好了 A,实际引入了 B。养成习惯:修完默认跑全量相关测试,把"只跑改的那个"当作偷懒的危险信号。

验证范围要匹配改动的影响面,不是无脑跑全量(那是另一种浪费):

  • 改了叶子函数(没人调用或只一处调用)→ 跑该函数 + 唯一调用方
  • 改了共享工具/被多处依赖的逻辑(utils、配置、类型定义)→ 跑所有调用方的测试
  • 改了核心数据流/公共组件 → 跑全量,甚至手动冒烟关键路径
  • 改动只影响自己(如函数内部重构、行为不变)→ 跑该函数测试即可

判断尺子:这次改动可能波及哪些代码? 影响面 = 验证范围。低估影响面(把共享改动当叶子改)是回归的常见源头;高估影响面(叶子改动跑全量)只是慢,不危险——拿不准时往大了跑。

循环要有刹车

修了 A 引入 B、修 B 又引入 A——这种循环不罕见。没有刹车的循环会无限转下去,越改越烂。预设停止条件:

  • 全绿:所有验证通过 → 成功,停。
  • 超最大轮次(如 5 轮)→ 停,承认当前方案走不通,退回去重新想(不是硬撑)。
  • 同一失败连续两轮:说明上次修复没生效或方向错 → 停,换思路。
  • 修复引入回归:新改动的代价大于收益 → 停,回退这次改动。
  • 无进展:几轮都在原地打转 → 停,把问题升级(求助/换方案/拆小)。

刹车不是放弃,是防止把"修不好"变成"越改越糟"。到达刹车条件时,正确动作是退回重新设计或求助,而不是继续在同一处硬磨。

常见错误

问题修法
没跑就声称完成("看着应该没问题")跑测试/类型检查/实际运行,用证据替代肉眼判断
修症状(末端兜底压住报错)向上游追溯根因,在最上游产生处修
为通过弱化检查(改断言/删测试/any/吞异常)红线不可越——修代码真正通过,而非改检查放行
把失败报告总结成"有个 bug"原样保留报错/行号/堆栈/复现步骤
修复无限循环、越改越乱预设刹车(轮次/重复失败/回归/无进展),到点停并退回
把合理兜底(可选字段)当 bug 修,或反过来问"空值何时出现"——有合理业务场景=兜底,说不清=bug
重构只验"能跑",不验"行为没变"重构要覆盖原代码处理过的所有边界,标准比新写更高
修复后只跑出问题的测试跑全部相关测试(调用方/共享逻辑/全量),防回归

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.