mcpField
P
polish-diff

polish-diff

github.com/jayden-dang开发153 次安装5 天前更新
代码仓库

关于 polish-diff

面向开发者的代码清理技能,从复用、简化、效率和实现层次四个角度审查指定 diff。它要求保持行为不变,只处理范围内的修改,并在完成后重新通过原测试套件。

主要功能

  1. 01从四个清理角度审查 diff
  2. 02保持行为和测试不变
  3. 03仅应用 diff 范围内的发现
  4. 04前后运行相同测试套件
  5. 05报告舍弃项和延期债务

适用场景

  1. 01在不改变行为的前提下重构改动
  2. 02查找重复或不必要的复杂代码
  3. 03提交前审查 diff
  4. 04记录范围之外仍有效的清理问题

安装

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

$npx skills add https://github.com/jayden-dang/skills --skill polish-diff

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

附带文件eval.jsonTESTS.md

详细介绍

Polish Diff

四个清理 Agent 从四个角度审查差异,然后由你应用它们的发现。交付成果是行为完全相同、代码更整洁,而不是报告,也不是错误修复。

这项技能由两条边界定义,二者都至关重要:

1. **行为不得改变。** 清理前通过的测试套件,清理后也必须通过,而且不能通过修改测试来实现这一点。若清理需要重写测试才能通过,那就不算清理。 2. **正确性错误不在范围内。** 不要主动寻找,也不要修复你偶然发现的错误。记录它们,并告知用户运行 `inspect-change`(如果问题已经存在,则运行 `root-cause`)。同时重构和修复的差异,评审时可能两者都不算。

1. 锁定差异 — 快速失败

运行 git diff @{upstream}...HEAD(如果失败,则依次尝试 git diff main...HEAD 和 git diff HEAD~1)获取待评审的差异。如果存在未提交的更改,或范围差异为空,也运行 git diff HEAD,并将工作区更改纳入范围——polish-diff 通常在提交前运行。作为参数传入的 PR 编号、分支或文件路径会取代上述所有操作。差异为空时立即停止并说明;绝不能让四个 Agent 去评审空内容。完成标准:差异非空,且已说明评审范围。

2. 记录通过状态基线

找出并运行覆盖已更改文件的测试套件,并在动手修改前记录结果。通过状态是你必须在第 6 步重现的基线。若此时测试未通过,说明分支已经损坏——停止并告知用户运行 root-cause;在测试失败的基础上做清理,会破坏唯一能证明清理保留了行为的证据。完成标准:测试套件通过,且记录了证明这一点的命令。

3. 并行派发四个清理 Agent

发送一条消息,包含全部四项派发内容,让它们并行运行,且互不影响彼此的上下文。所有 Agent 都必须只读——它们负责报告,由你来应用。每项任务说明不超过 400 个词,且绝不预先定性:不要说“不要标记”,也不要预先评定严重程度。

每个 Agent 接收差异、仓库路径,以及以下恰好一个审查角度。每项发现都必须包含 file:line、一行摘要、具体代价(重复了什么、浪费了什么,或增加了什么维护难度——绝不能是假设性的崩溃),以及明确的替代方案——应改用的具体辅助函数、更简单的写法或成本更低的替代方案。没有明确替代方案的发现不可操作,Agent 应将其舍弃。

复用

标记重新实现了代码库已有功能的新代码。搜索共享模块、工具模块以及更改附近的文件,并指出应改用的现有辅助函数。

简化

标记差异新增的不必要复杂性:多余或可推导的状态、略有变化的重复代码、过深的嵌套、遗留的死代码。指出能完成相同工作的更简单写法。

效率

标记差异引入的无效开销:重复计算或重复 I/O、相互独立的操作却按顺序运行、在启动阶段或热点路径上增加阻塞任务。同时标记由闭包或捕获环境构建的长生命周期对象——只要对象存续,它们就会使整个外围作用域保持存活;如果该作用域持有大型值,就会造成内存泄漏。应优先使用只复制所需字段的类或结构体。指出成本更低的替代方案。

抽象层级

标记在错误层级实现的更改。在共享基础设施上层层添加特殊情况,通常表明问题没有从根源解决——应优先泛化底层机制,而不是再添加一个特殊情况。指出应吸收这项更改的机制。

注释规范(由控制器执行;也可纳入简化)

这里仍适用默认零注释。如果差异中注释很多,或用户要求大幅清理注释 → 告知他们运行 /no-comments(不要代为调用)。否则:

  • 删除或重写: 重复说明下一行内容的注释;叙述控制流的注释;引用需求 ID 的注释;写着“按照计划/规范”的注释;重复说明任务的 TODO。
  • 保留: 代码本身无法体现的非显而易见的不变量、风险、协议/线路约束,以及“为何不采用显而易见的替代方案”。

完成条件:四个 Agent 均已提交报告(如果子 Agent 只负责四个审查角度,控制器可额外进行第五轮注释规范审查)。

4. 分类处理

将指向同一行或同一底层机制的问题合并——四个审查角度经常会从四个方面发现同一个问题。然后直接丢弃以下问题,无需争论:

  • 修复会改变可观察行为的任何问题(这属于设计变更;转交给 amend-feature 或 reroute-plan)
  • 需要在已锁定差异范围以外进行编辑的任何问题
  • 你认为属于误报的任何问题

为每项丢弃的问题记录一行理由。静默丢弃的问题,与从未收到的问题无法区分。完成条件:每项问题都已排入待处理队列,或记录为已丢弃并附上理由。

5. 应用修复

直接修复每项保留的问题,并从影响范围最小的开始。只修改已锁定差异中的文件。必需子技能:使用 test-first——其重构规范正是本步骤所需:测试保持不变,代码在其下方调整。完成条件:每项排入队列的问题均已修复,或已移入已丢弃列表并附上理由。

6. 证明行为保持不变

重新运行步骤 2 中的原命令。测试必须全部通过;对于此次清理,git diff 中唯一允许的测试文件变更,是满足以下全部三个条件的删除——任何其他测试文件行的新增或删除,都必须停止。必需子技能:使用 prove-claim——“清理看起来安全”不算证据;重构最容易让人在确信自己没有破坏任何东西时,实际破坏某些东西。若测试套件未通过,应撤销导致问题的修复,而不是继续修补。

允许的删除及其三个条件:如果测试唯一锁定的是简化审查中已作为死代码移除的代码,则可以删除该测试——对应目标已不存在;该行为仍由其他测试覆盖,且你要在步骤 7 的报告中指出该测试;并在报告中说明删除该测试。三个条件缺一不可,测试必须保留。绝不能重写、改换目标、重命名或移动测试;规则 1 禁止这种转移目标的做法,而“我把同一断言改为针对规范函数”正是这种做法。如果测试无法删除,就保留旧符号作为委托给规范实现的薄别名——重复的规则会消失,这才是发现的问题,而且测试套件完全无需改动。

完成条件:使用步骤 2 中通过的同一命令,测试套件再次全部通过;如果删除了任何测试,须在报告中指出该测试及替代覆盖。

7. 报告

说明修复了什么、丢弃了什么及原因;另外,单独列出 Agent 顺带发现的任何正确性 bug,并按规则 2 转交。

然后是第四个槽位:记入债务。丢弃原因是范围(不在固定 diff 范围内,是其他模块的问题)的条目,是有人认为确实存在、但有意不修复的问题;现在它只存在于这份报告中。对于每个此类丢弃项,都要发出以下区块——槽位名称与 record-debt 的 The entry 相同,但标题中不含 DEBT-N(/record-debt 会添加 ID)。请告知用户在上下文结束前运行 /record-debt。标记为误报的丢弃项,其原因已经完整记录,因此绝不记入债务。

### `<path>` — <one-line finding>

- **Found:** `<YYYY-MM-DD>` · polish-diff on `<branch or range>`
- **Cost:** <what this makes harder or riskier, concretely>
- **Deferred because:** outside the pinned diff
- **Fix shape:** <one line | Unknown>
- **Ticket:** none
- **Status:** open

没有答案的槽位填写 Unknown——绝不可省略该行。“只列出范围外的丢弃项”/“别凭空编造台账”不代表可以跳过这些槽位。在这里编造 **DEBT-N** 会造成冲突;不要这样做。

如果分流后没有留下任何问题,请说明代码本来就很干净。这也是一次成功运行,而不是失败;四个 Agent 什么都没发现,是实实在在的结果;为了证明这次审查有价值而硬找出一个问题,是唯一比完全没有发现还糟糕的结果。完成条件:已说明修复项/丢弃项/转交项/记入债务的条目——如果每个丢弃项都是误报,则记入债务的条目应为“无”。

内联备用方案(不具备子 Agent 能力时)

在同一上下文中,依次自行检查四个角度:复用、简化、效率、抽象层次。彻底完成一个角度并记录其发现后,再开始下一个;使用四个独立上下文的全部价值在于,每个角度都不会看到(并受其结论影响)其他角度的结果。在单一上下文中,只有先完成一个角度再开始下一个,才能尽可能实现这一点。步骤 1、2 和 4–7 保持不变;不能因为审查成本较低就省略步骤 6。

红线——绝不可

  • 修改测试,使整理后的代码能够通过测试
  • 修复“顺手发现”的正确性 bug
  • 修改固定 diff 从未涉及的文件
  • 应用无法用一行说明具体代价的发现
  • 未重新运行步骤 2 中的命令,就报告清理已完成
  • 因为四个 Agent 都没发现问题“看起来不对”,就凭空编造发现

自我开脱

想法事实
“这显然是个 bug——放着不管也太蠢了”那就应该进行正式审查,而不是在清理提交中顺手修复。将它交给 inspect-change;既重构 diff 又修复问题的代码,两方面都无法得到妥善审查
“测试断言了旧的内部实现,所以我更新了它”你改变了行为,也移开了原本能发现问题的标尺。撤销。如果确实必须修改测试,这就不再是润色 diff
“我只是让测试改为指向规范函数——断言完全相同,也没有失去覆盖率”这是最常见的违规方式,而且听起来最有道理。你删掉了那个挡路的测试,又写了一个新测试,而新测试并不能起到同样的作用。应将旧符号保留为精简别名:重复规则依然会被移除,测试套件也无需改动
“顺手改一下这三个文件会更整洁”固定 diff 之外就是范围之外。无法界定范围的清理,也就无法审查
“测试套件太慢了——只跑受影响的测试就够了”步骤 2 中记录的基线是你唯一的证据。范围更窄的重跑,只能证明比你即将声称的内容更少
“没有发现问题,所以我再仔细找找”确认代码本来就很干净,就是交付成果。凭空编造的问题,会让你为虚假的代价做出真实修改
“行为确实变了,但严格来说是变好了”这是披着清理外衣的设计变更。将它转交给 amend-feature,让它接受审查

评论

支持 Markdown