guardskills
amElnagdy/guard-skills · skills.sh 反应式 二次质量闸门

在交付前 拦住 LLM 的坏代码

guard-skills 是一组反应式二次质量闸门,在代码、测试、文档落地之前,系统性地拦截 LLM 反复犯的失效模式——过度防御、虚假成功、过早抽象、注释污染、参数爆炸。

# npx skills add amElnagdy/guard-skills · MIT · skills.sh

14
系统性失效模式
23
强制准则
8 步
交付前自检
5 guards
分层技能
向下探索
01
modes · three triggers

三种触发模式

每个 guard 技能(clean-code-guard / test-guard / docs-guard / wp-guard / woo-guard)都运行在三种模式之一。由用户请求决定激活哪一种。

Guard-Pass · 推荐

反应式复查

代码已生成 / 编辑 / 重构 / 修复之后运行。在呈现、提交或合并前,把 diff 或目标文件对照所有常驻准则检查一遍。

  • 编码 agent 写完或改完实现之后
  • 重构之后——必须严格保持行为不变
  • PR 呈现前、commit 落地前

触发语:"review this PR"、"is this safe to merge?"、"check this diff"、"should I commit this?"

Live · 显式

约束式写作

用户在一次有风险的编辑前显式调用 guard,则在写作时就套用同一批准则,写完后再跑交付前自检才展示结果。

  • 用户说 "use clean-code-guard while implementing this"
  • 有风险的结构性变更(抽取、抽象、重写)
  • 希望约束在生成过程中持续生效时

触发语:"use $clean-code-guard while you write"、"implement this endpoint using clean-code-guard"

Review · 被触发

结构化审计

用户要求 review / audit / critique / rate 代码时,对目标文件走完整评审模式清单,产出结构化发现报告。未被要求则不改代码。

  • 用户说 "review this PR" 或 "audit this code"
  • 面向正确性的代码评审——行为变更在范围内
  • 带严重度评级的结构化输出(Critical / Important / Nit)

触发语:"review"、"audit"、"critique"、"rate this code"、"assess this"

决策树:有代码被写或被改 → guard-pass;写之前主动调用 → live;用户要求 review/audit → review。绝不混用模式——review 不改代码,guard-pass 不产出发现报告。
02
failure modes · highest leverage

14 种系统性失效模式

这是杠杆最高的检查项。14 项中有 8 项追溯到同一根因:模型偏向于多写代码、多加参数、多设防御、多搞抽象——任何东西,就是不肯只写规格要求的最小实现。每次交付前都要走一遍。

表 02 · 14 种模式 · 模式 / 自检规则 / 来源
#模式规则(自检)来源
1吞掉失败的 catch-all 错误处理只 catch 你能恢复的那个具体错误类型。除非契约写明,绝不用宽泛的 catch any,也不从 handler 返回 null/空成功。Karpathy;LLM 错误抑制实地报告
2为不可能情况加防御性守卫不要为类型注解或调用方契约已排除的值再加 null 检查或运行时类型检查。相信契约。arXiv 2409.19182
3过早抽象除非今天就存在两个及以上具体实现,否则不要引入 interface / 抽象类 / factory / registry / strategy / plugin 模式。只有一个实现 = 内联。Fowler, "Patterns for Reducing Friction"
4注释污染注释解释 why,绝不解释 what。删掉复述代码的注释、步骤编号脚手架、复述签名的 docstring。HN #43929768;arXiv 2402.13013
5复制代码而非复用写 ≥5 行的块之前,先在代码库里搜相似的现成函数。复制知识是违规;复制能匹配现有 helper 的文本也是违规。GitClear 2025 — 2.11 亿行,2021–2024 增长 8×
6幻觉 API 与依赖包每个 import 与外部 API 调用都必须对照实际安装的版本核实。读包、查 lockfile,或 import 后 inspect。绝不凭"应该有"去调方法。USENIX Security '25 — 16 模型,平均 19.6% 幻觉率
7泛化、无意图的命名禁用 data result item temp value obj info helper manager handle_* process_* do_*(除非有限定词)。名字必须揭示意图。arXiv 2512.01141;arXiv 2510.03178
8长函数干多件事一个函数只做一件事。硬上限:≤50 行、≤4 参数、圈复杂度 ≤8。规格要求 N 件事就产出 N 个函数加一个小 composer。GitClear 2025 — 文件 142→267 行;arXiv 2512.11922
9参数爆炸函数参数达到 5 个就停下,引入一个有类型的 request/config 对象(record、struct、DTO)。不要继续堆位置参数。arXiv 2304.10778;Fowler 过度热心模式
10与周围代码不一致在文件里写之前,先读这个文件和至少一个邻居。对齐大小写、import 风格、错误处理模式、日志风格。复用既有工具。Pullflow "The Context Illusion";Honeycomb 实地报告
11死代码、未用 import、半成品跑 linter 或 grep,扫未用 import、未用符号、不可达分支、"以防万一"的导出。交付前删掉。arXiv 2411.01414;GitClear "新增码远多于删除码"
12宣告成功——生产代码里的 mock 兜底规格说要做真实工作的函数,绝不返回硬编码"成功"值或夹具数据。实现不了就显式失败并说明缺什么。Fowler "Reducing Friction";Claude Code #6984
13看似合理实则错误的代码任何边界、范围、差一、null 语义的问题,先在注释里写出 case 枚举。绝不复制相似函数再改——从规格重新推导。arXiv 2411.01414;Katanaquant "Plausible Code"
14YAGNI 违规——投机式可配置没有当下调用方就别加可选参数、config flag、env var、feature toggle。发现自己在加 enable_* use_* *_mode 就删掉,发布具体行为。Fowler "YAGNI";HN 防御代码讨论
横切根因:14 种失效模式中的 8 种(1、2、3、9、12、14,外加 8 和 11 的部分)来自同一个偏差——模型因多写代码而被奖励。解药是克制。写每一行之前问一句:规格今天真的需要它吗?不需要,就别写。
03
imperatives · always applied

23 条强制准则

在 guard-pass 与 live 模式下,这些规则适用于每一次代码变更。它们是命令式的,不是建议。

01 命名揭示意图

绝不在无限定词时用 data result item temp value obj info helper manager utils 或 handle_*/process_*/do_*。名字必须回答它为何存在、做什么。(Clean Code Ch.2)

02 函数保持小

目标 ≤20 行、一个抽象层级、一件事。若能抽出一个名字不复述函数体的子函数,说明父函数干了不止一件事。(Clean Code Ch.3)

03 四参数是硬上限

到第五个就停下,引入 request/config 对象(record、struct、DTO)。绝不用布尔 flag 参数——拆成两个函数。

04 不用输出参数

函数要么返回值(query),要么有副作用(command),绝不两者兼有。command 用动词,query 用名词或 getter 式名字。(CQS)

05 注释解释 why

删掉任何复述下一行的注释。删掉步骤编号脚手架。删掉注释掉的代码——版本控制就是干这个的。(Clean Code Ch.4)

06 匹配文件既有风格

写之前读你要改的文件和至少一个邻居。对齐大小写、import 顺序、错误处理、日志、HTTP/DB client 选型。不要引入第二套模式。

07 每模块一个 actor

一个类只对一个利益相关方群体(Accounting、Auth、Reporting)负责。两个不相关子系统都伸手进同一个类,就拆开。(SRP, Uncle Bob 2014)

08 靠新代码扩展,而非改

若加新变体要在既有函数里再加一个 type-tag 分支,先重构成 registry、strategy 或多态分派。(OCP)

09 子类不拒绝父契约

绝不为发"未实现/不支持"信号而 override 方法。绝不在 override 里强化前置条件或弱化后置条件。要这么做,说明继承用错了。(LSP)

10 抽象归属于客户端

引入 interface、protocol 或抽象契约时,放在消费它的包里,而不是紧挨着具体类。(DIP)

11 删重复知识,非重复文本

两个长得像但编码不同规则的函数不是 DRY 违规。一条规则同时出现在 代码+文档+schema 才是。(Pragmatic Programmer, "DRY")

12 错抽象比重复更糟

抽象若为每个调用方的特例堆满了分支,把它重新内联回调用方,删掉死分支,再重新抽象。(Sandi Metz, "The Wrong Abstraction")

13 复杂度上限

圈复杂度 ≤10,嵌套深度 ≤5。超限前先重构。(McCabe 1976)

14 不做任何投机

没有当下调用方就别加可选参数、config flag、env var、feature toggle、interface、factory 或基类。发现自己加 enable_* use_*_v2 *_mode 就删掉,发布具体行为。(Fowler, "YAGNI")

15 绝不用宽泛 catch 吞错

只 catch 你能恢复的具体错误类型。无法恢复就让错误传播。除非函数契约写明,从 catch handler 返回 null/none/空成功是禁止的。(Karpathy)

16 不为不可能情况加守卫

不要为声明类型或调用方契约已排除的值再加 null 检查或运行时类型检查。相信契约。(arXiv 2409.19182)

17 核实每个 import 与外部调用

调库方法前,确认它在已安装的版本里存在(读包、查 lockfile,或 import 后 inspect)。不要凭 API "应该长什么样"生成代码。(USENIX Security '25)

18 生产代码无硬编码成功/mock

规格说做真实工作的函数,绝不返回 {"status":"ok",...} 或罐头数据。实现不了就用语言的 unimplemented/unsupported 机制显式失败并说明。绝不为让测试通过而禁用、跳过或弱化它。(Fowler, Claude Code #6984)

19 重新推导,不从相似复制

想复制一个函数改改时,停下。从规格重新推导。差一和错 null 语义的 bug 几乎都从"复制相似"溜进来。(arXiv 2411.01414)

20 写前先枚举边界 case

任何范围、差一、null/空/一个/多个、奇偶、unicode/byte 边界,先在注释里写出 case 清单。逐个在代码里覆盖再往下。

21 交付前清除死代码

跑 linter 或 grep,扫未用 import、未用符号、不可达分支、"以防万一"的导出,删掉。今天没人调的函数不许为"将来"活着。

22 先读后写

在陌生仓库写之前,读你要改的文件、一个邻居,以及任何项目规则文件(CLAUDE.md、AGENTS.md、README 的 conventions 段)。用项目既有的 helper、错误类型与日志。

23 重构保持可观察行为

相同输入产出相同输出、抛相同异常、相同副作用、相同顺序保证。重构时发现 bug,单独标记并先问再改。重构定义为改内部结构使其更易理解而不改变可观察行为(Fowler, Refactoring)。修 bug 与重构是两个操作——绝不打包。

04
self-check · before delivery

交付前 8 步自检

在向用户展示你写或改的任何代码之前,跑这份清单。每一步都答"是"才能交付,否则先修。

步骤 1 走准则 1–23 对照 diff

常驻准则里的每一条都适用于每次变更。扫完整个 diff,确认 23 条无一被违反。逐个修掉。

步骤 2 新函数数一数

行数 ≤20?参数 ≤4?复杂度感觉 ≤10?名字揭示意图?套用准则 1–3 的硬上限。超限的函数几乎一定多做了一件事或藏了抽象。

步骤 3 新注释问一句

它解释 why 吗?若解释 what,删掉。准则 5 是过滤器:复述下一行的注释只加噪声不加信号;残留的步骤编号脚手架也删。

步骤 4 新错误处理

catch 的错误类型够具体吗?handler 除了静默返回还做别的吗?准则 15 与 18:无文档化恢复路径却返回 null/空成功就是失败。只 catch 你能行动的。

步骤 5 新抽象

interface / factory / 基类 / registry:今天有第二个具体使用方吗?没有就内联。准则 3 与 12:单实现的抽象是过早;分支按调用方堆积的抽象是错抽象。

步骤 6 读了吗

你读了要改的文件和至少一个邻居吗?风格对齐了吗?准则 6 与 22:风格不一致是 LLM 代码评审三大高频发现之一。写前先读。

步骤 7 有硬编码 "ok" 吗

有没有硬编码 "ok" 返回或夹具数据?有就换成真实实现,或显式的 unimplemented/unsupported 失败。准则 18:这是最危险的 AI 模式——让代码看似能跑却交付虚构,必须交付前抓住。

步骤 8 若是重构

你改了可观察行为吗?改了就说明你打包了 bug 修复——拆出来问用户。准则 23:重构与修 bug 是两个独立操作,混在一个 diff 里两者都没法干净评审。

05
review · structured findings

评审模式输出模板

当用户要求 review / audit / critique 代码时,产出这一确切格式。评审模式下未被要求不改代码。交付发现前走完全部五个小节。

review-output.md · 输出模板
# Code review: <file or scope>

## Summary
<2–3 sentence verdict: ship / needs work / rewrite>

## Critical findings
<must-fix before merge>
- **<short title>** — `<file>:<line>`
  Evidence: <quoted code or behavior>
  Principle violated: <e.g., LSP, catch-all error swallowing>
  Suggested fix: <concrete>

## Important findings
<should fix but not blocking>
- ...

## Nits
<style, naming, minor structure>
- ...

## What's good
<at least 2–3 specific positives — naming, structure, test coverage>

## Self-check coverage
- [ ] Walked Section A (naming & functions)
- [ ] Walked Section B (comments & formatting)
- [ ] Walked Section C (SOLID)
- [ ] Walked Section D (DRY/KISS/YAGNI)
- [ ] Walked Section E (AI failure modes)
表 05a · 严重度定义
严重度示例
Critical安全漏洞、正确性 bug、数据丢失、吞掉的异常、硬编码 "success" 返回
ImportantSOLID 违规、过早抽象、参数爆炸、泛化命名、DRY 违规
Nit风格不一致、循环外的单字母命名、公共 API 缺少 docstring 契约
表 05b · 小节走查顺序
小节检查
A — 命名与函数泛化命名、函数大小、参数数量、CQS 违规、布尔 flag
B — 注释与格式复述型注释、步骤编号脚手架、注释掉的代码、风格不一致
C — SOLIDSRP 多 actor 模块;OCP type-tag 分派膨胀;LSP 不支持-操作 override;ISP 胖接口;DIP 错层 import
D — DRY/KISS/YAGNI知识重复、错抽象分支、圈复杂度 >10、嵌套 >5、投机式可配置
E — AI 失效模式全部 14 种模式。与 A–D 交叉核对。杠杆最高的小节。
06
skills · the five guards

技能参考

每个 guard 技能针对一类特定的 agent 产出。它们层叠:平台专属 guard(wp-guard、woo-guard)在 clean-code-guard 之后运行。

● clean-code-guard

任意语言

LLM 代码异味、SOLID/DRY/KISS/YAGNI、14 种 AI 失效模式。

● test-guard

pytest · PHPUnit · Jest · Go · WP/Woo

mock 滥用、重复测试、断言实现细节。

● docs-guard

README · docstring · API 文档 · changelog

幻觉符号、坏掉的示例、文档与代码漂移。

● wp-guard

WordPress 插件 · 主题 · REST · AJAX

转义、消毒、nonce、capability、预处理查询、i18n。

● woo-guard

WooCommerce 扩展 · 结账 · 订单

HPOS 安全访问、CRUD 优于 meta、金额错误、服务端校验。

表 06 · 配对指南
Guard能抓什么配对
clean-code-guardLLM 代码异味、过度抽象、宽泛错误吞噬、坏命名、SOLID/DRY 违规平台专属 guard
test-guardmock 滥用、重复测试、断言实现细节、什么都抓不到的测试测试 helper 含真实逻辑时配 clean-code-guard
docs-guard幻觉符号、坏示例、文档与代码漂移、不可验证声明任何行为被写进文档的 guard
wp-guard转义、消毒、nonce、capability、预处理查询、i18n、查询/缓存错误clean-code-guard;出现 Woo API 时配 woo-guard
woo-guard直接读订单 meta、HPOS 破坏、缺兼容声明、绕过结账、金额错误WordPress 层配 wp-guard
07
examples · bad / good

正反例速查

最常见的失效模式,配上具体的 before / after。

失效模式 1 — catch-all 错误吞噬

BAD · 数据库宕机现在和"用户没邮箱"无法区分
getEmail(userId):
  attempt:
    user = userStore.get(userId)
    return user.email
  catch anyError:
    return null
GOOD · 存储错误传播;null 只表示用户没邮箱
getEmail(userId):
  user = userStore.get(userId)  # errors propagate
  return user.email

失效模式 2 — 为不可能情况加防御守卫

BAD · 契约说 orderItems 是集合;这些守卫一个都触发不了
total(orderItems):
  if orderItems is null: return 0
  if orderItems is not a collection: return 0
  return sum(order.amount for each non-null order in orderItems)
GOOD · 相信契约
total(orderItems):
  return sum(order.amount for each order in orderItems)

失效模式 3 — 过早抽象

BAD · 只有一个支付处理器;抽象接口与工厂纯属仪式
PaymentProcessor interface
  charge(amount)
CardPaymentProcessor implements PaymentProcessor
  charge(amount):
    return paymentProvider.createCharge(amount).id
PaymentProcessorFactory
  create():
    return new CardPaymentProcessor()
GOOD · 一个具体函数,零仪式
charge(amount):
  return paymentProvider.createCharge(amount).id

失效模式 7 — 泛化、无意图命名

BAD · 没有一个名字揭示意图
processData(data):
  result = []
  for item in data:
    temp = item.value * 2
    result.add(temp)
  return result
GOOD · 名字回答函数为何存在、做什么
doublePrices(orders):
  return orders.map(order -> order.priceCents * 2)

失效模式 9 — 参数爆炸

BAD · 应该用有类型的 config 对象
sendEmail(to, subject, body, retry=true, backoff="exp",
          html=false, fromAddress=null, encoding="utf-8",
          internal=false, verbose=false)
GOOD · 有类型的 request 对象可干净扩展
EmailRequest
  to
  subject
  body
  html = false

sendEmail(request: EmailRequest)

失效模式 12 — 宣告成功,mock 兜底

BAD · 作为实现交付,函数体是虚构
getUserBalance(userId):
  return 1000  # TODO: actual provider call
GOOD · 显式失败,明确说明缺什么
getUserBalance(userId):
  raise NotImplemented("Wire to billing.getBalance() after auth is available")

失效模式 13 — 看似合理实则错误(复制相似)

BAD · 奇数长度数组差一;静默丢掉 items[0]
median = (values[values.length / 2] + values[values.length / 2 + 1]) / 2

# BAD — silently drops items[0]
for index from 1 to items.length - 1:
  ...
GOOD · 先枚举 case,再写代码
# cases: empty / one / even / odd
median(values):
  sorted = values.sort()
  mid = sorted.length / 2
  return sorted.length % 2 == 0
    ? (sorted[mid-1] + sorted[mid]) / 2
    : sorted[mid]
08
sources · the evidence

来源与证据

每条规则背后的研究与实地报告。下表把每个来源与它支撑的声明对应起来。

表 08 · 来源 / 支撑的声明
来源支撑的声明
GitClear 2025 — AI Copilot Code Quality2021–2024 代码重复增长 8×;函数大小 142→267 行;复杂度 4.2→8.1
arXiv 2409.19182 — AI-Generated Code Considered Harmful防御代码过度使用;为不可能情况加运行时类型检查
USENIX Security '25 — Package Hallucinations16 模型,平均 19.6% 包幻觉率;商业 ~5%,开源 ~21%
Fowler — Patterns for Reducing Friction过度热心、测试未过却宣告成功、暴力修复
Fowler — YAGNI投机式可配置的成本;无调用方的可选参数
Metz — The Wrong Abstraction重新内联规则;共享抽象中按调用方堆积的分支
arXiv 2411.01414 — LLM Code Generation Mistakes7 类分类法;复制相似的语义错误;半成品
arXiv 2402.13013 — Code Needs CommentsLLM 注释平均 ~5 词 vs 作者 19 词;回答 "what" 而非 "why"
arXiv 2512.01141 — Neural Variable Name Repair泛化标识符是命名修复模型的明确目标;LLM 代码过度产出它们
arXiv 2510.03178 — When Names Disappear语义名在生成时充当锚点;泛化名劣化代码质量
arXiv 2512.11922 — Vibe Coding in Practice典型症状:300 行函数处理四个不相关关注点
arXiv 2304.10778 — Copilot/CodeWhisperer/ChatGPT 对比参数爆炸、LLM 辅助提交中的函数复杂度增长
HN #43929768注释污染是让 agentic 代码变丑的最常见因素
Claude Code #6984 — Systematic Mock Data Generation Bias生产代码中硬编码 "success" 返回与夹具数据
guardskills · 克制即质量
amElnagdy/guard-skills · 面向 AI 代码 / 测试 / 文档的反应式质量闸门
安装:npx skills add amElnagdy/guard-skills · License MIT
github.com/amElnagdy/guard-skills ↗