mcpField
C
code-humanizer

code-humanizer

github.com/leonardnju开发88178 次安装13 周前更新
代码仓库

关于 code-humanizer

code-humanizer 是用于审查和清理 AI 生成代码结构性问题的 Skill,也可在实现改动时预防此类问题。它以测试套件验证行为保持,并要求先扫描和报告既有代码问题。

主要功能

  1. 01扫描代码结构性问题
  2. 02按模式分类并评估严重程度
  3. 03先报告再清理既有代码
  4. 04通过测试验证行为保持
  5. 05实现期间预防新增问题

适用场景

  1. 01审查仓库或变更中的重复实现
  2. 02在维护者批准后清理特定模式
  3. 03编写功能时避免不必要的抽象和防御代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/leonardnju/code-humanizer --skill code-humanizer

安装后在 Claude Code 中输入/code-humanizer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.zh.md
.gitignore
LICENSE
README.md

详细介绍

Code Humanizer

从代码仓库中移除 AI 生成代码的痕迹,或使用 Guard 模式防止这些模式出现在当前更改中。用于处理文本的 humanizer 会移除 AI 写作模式;本工具处理 AI 编码模式——当 Agent 优先考虑“测试通过”而非“代码库保持健康”时留下的结构性债务。

**核心原则:**AI 代码垃圾并非难看的代码,而是那些能够运行却会损害代码仓库的代码:它们重复实现已有功能,添加无人要求的抽象,吞掉本应暴露的错误,并为不可能发生的情况做防范。与文本不同,代码有判定标准:由测试套件决定什么叫“保持语义不变”。请始终使用它。

铁律

规则 1–4 适用于模式 A/B 中对既有代码的清理。在 Guard 模式中,这些规则适用于实现完成后的任何清理,不适用于所请求的功能本身。规则 5 适用于所有模式。

  1. **绝对要保持行为不变。**会改变行为的“清理”就是披着好意外衣的 bug。这包括错误类型和错误发生时机——把意外的 AttributeError 换成“更好”的 ValueError,会改变所有捕获该错误的调用方所观察到的行为。如果发现潜在 bug,或难看但不可或缺的行为:在报告中指出;绝不要把它作为清理的一部分悄悄修复。
  2. 没有测试 → 不做清理改动。先运行测试套件。如果测试套件不存在、未通过,或未覆盖要清理的既有代码,你只能报告该债务(模式 A)。可以先提议编写特征测试。这并不禁止在测试不完整的项目中实现所请求的更改;但要报告验证方面的缺口。
  3. **重写既有代码前先报告。**默认使用模式 A(扫描 → 报告)。只有维护者批准,或明确要求修复时,才进入模式 B(修复)。Guard 模式可以直接避免或移除当前更改引入的代码垃圾。
  4. **每个清理提交只处理一类模式。**每个移除既有代码垃圾的提交只处理一种类型,并通过完整测试套件。测试失败就回退该提交——不要通过修改无关代码来“向前修复”。在 Guard 模式下,普通功能提交无需按模式拆分,因为预防措施与实现不可分割。
  5. **判断重复前先搜索。**在扫描或实现之前,先在脑中建立一份代码仓库现有辅助工具的索引(搜索 utils、helpers、common、验证器和现有基类)。不了解已有内容,就无法识别重复实现。

模式目录

每项发现的严重程度:0 不存在 · 1 存在但有充分理由(→ 豁免,不要改动)· 2 轻微债务 · 3 明显债务,会增加未来的维护成本 · 4 严重,会破坏语义或架构边界。

第 1 级 — 重复与重新发明

1. 重复实现已有辅助工具 (AI 代码的典型特征) **迹象:**新增私有函数的函数体与 utils/helpers/同级模块中的代码相似;代码仓库已有对应实现的正则表达式/验证/解析/格式化代码块;新增代码没有从其所属的软件包导入任何内容。 **问题:**Agent 从提示词出发编写代码,而不是从代码仓库出发。每个重复实现都会让未来的修复分道扬镳。

# Before — repo already has utils.validate_email
def _is_valid_email(s):
    pattern = r"^[\w.+-]+@[\w-]+\.[\w.]+$"
    if re.match(pattern, s):
        return True
    return False

# After
from .utils import validate_email

2. _v2 / _new / _impl 克隆 迹象:foo 和 foo_v2 同时存在;使用 enhanced_、improved_、new_ 前缀;复制粘贴的函数体只改动了一个分支。 **问题:**Agent 不敢修改原有实现,于是现在出现了两个事实来源。应合并两者(使用参数或更新后的函数体),并只保留一个名称,除非正在进行有文档说明的迁移。

3. 重新发明标准库或已安装的依赖 **迹象:**手动实现 groupby、通过 JSON 深拷贝、手动解析 URL、自行编写日期计算;而 stdlib 或已安装的依赖中已有等效实现。

第 2 级 — 推测性架构

4. 单一实现的抽象 信号: ABC / 接口 / Protocol 只有一个具体类;注册表或工厂只有一项注册;“可插拔后端”只在一个调用点使用。 问题: 为从未提出的未来需求增加灵活性。将其内联;等出现第二种实现时再恢复抽象。

# Before: AbstractReportBackend + BackendRegistry + TextReportBackend (3 classes, 40 lines)
# After:
_BACKENDS = {"text": lambda rows: "\n".join(map(str, rows))}

5. “留待将来使用”的死代码 信号: 没有调用点的辅助函数;没有调用方传入的参数;声称“为便于扩展而提供”的 export_* / *_to_dict;写着灵活、可扩展、无缝的文档字符串。 问题: 不可达代码仍会增加审查负担、搜索结果和虚假的信心。删除它——git 会记住。先在整个仓库(以及脚本和模板)中搜索相关用法。

6. 毫无增益的封装 信号: 函数体只有一次参数完全相同的调用;类继承后只把所有内容交给 super()。

7. 针对本地情况的配置/API 泛滥 信号: 新增全局标志、配置字段、CLI 参数或公共参数,却只在一个地方读取;模块级常量只有一个函数会读取。 问题: 每个全局开关都会永久扩大状态空间。将其设为局部变量,或设为唯一需要它的函数的参数。

第 3 级 — 防御性冗余

8. 宽泛地吞掉异常 信号: except Exception: / 裸 except 返回默认值、不记录日志或直接 pass;.get() 链把错误悄悄转换成错误输出。 问题: 将崩溃(明显、可调试)变成数据损坏(隐蔽)。将捕获范围缩小到实际可能发生的异常,或让异常继续抛出。注意——这是行为变更;可能需要维护者批准(规则 1)。

9. 缺乏依据的 try-import 回退 信号: try: import fast_x except ImportError: import x,但没有基准测试、打包元数据中没有 extras 条目,也没有测试覆盖回退路径;对并非可选的依赖使用可选依赖处理逻辑。 问题: 两条代码路径,却只测试了一条。如果依赖很重要,就声明它;如果不重要,就移除它。

10. 属性探测链 信号: 使用 hasattr / getattr / isinstance 层层判断,以接受“字典或对象,或者也许是 None”;每次访问字段时都复制粘贴相同的探测表达式。 问题: Agent 没有检查这里实际传递的类型,所以什么都接受。找出真实类型(测试会告诉你),然后针对它编写代码。

11. 多余的谨慎式重新校验 信号: 对刚刚构造的值检查 if x is not None;重复检查类型系统或上游关卡已经保证的不变量。

第 4 级 — 噪声

12. 复述代码的注释 信号: 注释只是复述下一行(# 用换行符连接各行);写给审查者看的注释(# 此更改确保了正确性);Agent 在同一个 PR 中编写并解决的 TODO。 规则: 注释只有在说明代码无法表达的内容(约束、不变量、为何不采用显而易见的做法)时,才值得占用一行。

13. 模板化文档字符串 信号: 文档字符串只是函数名加空格(def get_user(): """获取用户。""");营销式形容词(稳健、全面、无缝)。

14. 无用导入、未使用变量、装饰性横幅 信号: 删除旧尝试后遗留的导入;# ===== SECTION ===== 横幅;标识符 / 日志行中使用 emoji;遗留的 print / 调试日志。

第 5 级 — 测试冗余(默认仅报告)

15. 断言模拟对象的测试 — 每个协作者都被模拟,断言检查模拟对象是否被调用;测试永远不会因真实原因而失败。 16. 琐碎或重复的断言 — 断言字面量,或用三个名称重复测试同一个用例以虚增覆盖率。

不应标记的情况(误报防护)

严重程度为 1 = 有正当理由。问题不在于模式的形式,而在于缺乏正当理由。标记之前,先查找是否有合理解释:

  • 有理由的回退方案/兼容垫片 — 有文档记录的平台差异、打包的额外功能(pip install pkg[fast])、迁移期间的版本门控。关键在于缺乏正当理由,而非回退方案。
  • 信任边界处的防御性代码 — 解析用户输入、网络负载、插件提供的对象。数据不可信时,探测和宽泛捕获错误完全合理(但仍应记录日志,而不是使用 pass)。
  • 实际插件系统中的注册表/抽象基类 — 如果入口点会动态加载实现,那么仓库内只有一个实现并不意味着系统只有一种实现。
  • 有经过衡量的理由而重复代码 — 热路径上的代码副本附有基准测试说明;有意保持同步的 vendored 代码。
  • 文档记录的迁移期间使用 _v2 — 合并前检查 git 历史/CHANGELOG。
  • 会记录日志且附有注释的吞掉错误 — 有意作出的弹性决策应由维护者日后重新审视,而不是由你处理。
  • 你单纯不喜欢的风格。 此技能消除的是结构性债务,而非格式偏好——那是 linter 的职责。

拿不准时:按严重程度 1–2 报告,不要修复。留意问题是否成簇出现——一条解释性注释不算什么;同一个 PR 中同时出现解释性注释、仅有单一实现的注册表、一个 _v2 和一个未使用的导出,那就是自白。

工作流

模式 A — 扫描(默认):

  1. **Oracle 检查:**运行测试套件;记录通过情况以及目标文件的大致覆盖率。
  2. **索引:**梳理仓库现有的辅助工具和抽象(为模式 1 提供依据)。
  3. **扫描:**对照目录检查目标范围(差异、PR、模块或整个仓库)。对每项发现记录:模式编号 · 文件:行号 · 严重性 · 证据(一行) · 建议的修复 · 行为风险(无 / 错误类型 / 需要维护者处理)。
  4. **报告:**按模式归类发现,汇总每个文件的严重性,并列出豁免及其理由。最后给出建议的修复顺序(优先处理严重性最高、行为风险最低的项目)。

模式 B — 修复(获准后): 5. 按获准的顺序逐个处理模式类别:修复所有实例 → 运行完整测试套件 → 提交(deslop: <pattern> (#N) — <n> instances)。测试失败则撤销提交。 6. 任何存在行为风险的项目(错误类型、吞掉异常、未知键路径)都要单独作为明确标注的提交提出,或保留为报告项——绝不能与安全清理混在一起。 7. **审计:**重新扫描结果,并问自己:“还有什么会让审查者觉得这是 AI 写的吗?”修复或报告剩余问题。 8. **总结:**按模式统计移除数量、代码行数变化、已遵守的豁免,以及待维护者处理的行为风险项目。

模式 C — 防护(实现期间):

当用户要求在实现变更时防止 AI 编码潦草问题,就进入防护模式。这是一层精简的预防措施,不是通用的编码方法论。它将同一目录应用于当前任务的实现决策和最终差异。除非用户提出要求,否则不要将其扩展为全仓库清理。

编码前 — 从仓库现状出发:

  1. 创建新工具之前,先搜索现有的辅助工具、实用程序、同类实现、基类、验证器和已安装依赖项。
  2. 沿着变更路径追踪实际的类型、不变量和错误行为。不要用探测链或宽泛的回退逻辑来弥补未知情况。
  3. 明确范围:探索性代码、内部模块,还是稳定的公共边界。评估其形态之前,先查找已记录的迁移、兼容性要求和实际的插件加载情况。

编码期间 — 遵循五条决策规则:

  • 优先复用,而非重造(模式 1–3):扩展或调用仓库已有的实现;不要另起炉灶编写辅助工具,也不要重复实现标准库行为。
  • 优先具体,而非抽象(模式 4–7):局部需求就留在局部;在出现真正的第二个实现之前,不要添加抽象、注册表、全局开关或公共 API。
  • 先了解,再防御(模式 8–11):根据实际契约编写代码;防御性灵活性只适用于真正的信任边界,而不是类型尚未查明的任意位置。
  • 解释原因,而非描述内容(模式 12–14):注释记录约束和不明显的原因;删掉叙述性文字、样板内容和实现残留。
  • 测试行为,而非脚手架(模式 15–16):验证对外可见的重要行为和失败情形,而不只是断言已调用模拟对象。

编码后 — 审查差异,索引仓库:

  1. 运行相关测试,并仅对照目录检查当前差异。重复代码检查仍需搜索整个仓库。
  2. 修复当前变更引入的安全潦草实现。不要顺手重构无关的既有问题;应另行报告。
  3. 简要记录有充分理由的豁免。只有在仍存在有意义的技术债或行为风险时,才展开为完整的发现列表。
  4. 最后给出简明的防护审计,例如:复用了现有辅助工具;未新增推测性 API;有一项探索性豁免;测试通过。
探索不是生产环境的技术债

探索阶段可以合理地暂时重复代码、硬编码值、并行保留多个变体,或使用粗略脚本,尤其是在 experiments/、scratch/、notebooks/ 和 prototypes/ 目录下。如果这些做法范围受限且是有意为之,应将其视为严重性 1 级问题。当代码进入核心包、稳定 API、共享模块或准备合并的路径时,这种豁免便不再适用。Guard 模式应为探索保留空间;在硬化阶段,临时分支才会合并,并开始适用常规目录。

范围: 对于 PR/差异,只扫描已更改的文件,但要对照整个代码库检查重复内容。对于整个代码库,逐个模块检查;提出检查顺序,并由维护者决定是否删减。在 Guard 模式下,除非请求了更广泛的清理,否则应将修改和事后检查限制在当前任务的差异范围内。

常见错误(真实案例)

错误实际情况
“这个错误类型显然是意外的——我来改进一下”这是行为变更。调用方会捕获特定异常。请报告此问题。
删除被“闲置”的辅助函数,而脚本/模板/反射机制可能会用到它删除模式 5 相关内容前,先用 grep 搜索所有内容,包括非代码文件。
一次大型提交修复 9 种模式无法审查,也无法回滚。每次提交只处理一类模式。
只运行一次测试套件就开始修复你无法判断“是我弄坏了”还是“它本来就坏了”。先运行预检。
在信任边界处重写有效的防御性代码不可信输入是唯一应该保持高度谨慎的地方。
把问题目录当作尽可能多找问题的清单目标是让代码库更健康,而不是追求问题数量。严重性 1 级的问题应保留。

评论

支持 Markdown