场景:10 周,13,147 条 commit

AI 辅助开发把代码的累积速度提高了一个量级,随之而来的问题是项目越写越“堆”:功能在快速扩张,结构在失去秩序。最直觉的应对是在 prompt 里加约束——“做最小实现”“不要过度抽象”。本文的结论是:这类事前限制控制不了膨胀,起作用的是事后治理——用固定门禁拦住可机械检测的结构问题(坏味道,如重复代码与死代码),用定期重构和去重抽象控制长期累积。核心证据来自 deepseek-harness 的公开 commit 史。

deepseek-harness(下文简称 DSH)是 DeepSeek 在 GitHub 上公开的仓库,在 2026-06-10 至 2026-08-21 的 10 周里积累了 13,147 条 commit,峰值一天 889 条。commit 主题与分支名中留有大量 AI 编码代理参与的痕迹(codex/ 分支前缀、.agents/ 目录)。这些数字全部来自公开数据,附录给出了可复现的统计命令,读者可以自行验证。

每周 commit 数

commit 史数据:三个反直觉的分布

提交类型按 commit 主题首词归类统计(命令见附录):

类型数量占比
Merge5,89145%
fix2,49019%
docs1,43511%
test1,0288%
feat7456%
refactor4944%
revert360.3%
其他1,0288%

提交类型分布

三个反直觉的发现:

第一,45% 的 commit 是 Merge,不是功能提交。合并是最大宗,说明开发不是单线程追加,而是大量并行分支持续汇入主干。一个仓库的形态是众多并行流合并出来的——这正是“单点约束难以控制全局结构”的机制原因。

第二,revert 只有 36 条,占 0.3%。靠“写错就回滚”纠错的项目,回滚不会这么少。36 条说明纠错不依赖回滚:提案在裁决阶段被否掉(archived / rejected),不合规的改动被门禁挡在合并之前,剩下的问题由后续小步修改向前消化。

第三,docs 占 11%,约每 9 条 commit 就有 1 条涉及文档。文档是日常流程的一部分,跟着代码同步演进,而不是收尾阶段的事后补写。这与“AI 写太快,文档必然滞后”的常见预期相反。

删除是制度化动作:净删重构与 26 条简化分支

只看类型分布容易得到“只增不删”的印象。删除的证据在 refactor 里,而且是净删除主导:

  • refactor(image): remove region reads —— +132 / -1,040 行,54 个文件
  • refactor(attachment) —— +612 / -748 行,68 个文件

两条都是单主题重构:移除一组区域读操作、重构 attachment 模块,净效果都是行数大幅下降。

更系统的证据是 26 条以 codex/simp- 开头的简化分支。这些分支按顺序堆叠成链:

simp-hide-concrete-agent-loop → simp-hide-subagent-internals → simp-unify-agent-session-id → simp-compaction-surface → simp-trim-hook-snapshot-noise

从名字看,每一步是同一个动作:把具体实现藏到接口后面(hide-concrete-agent-loop、hide-subagent-internals),统一重复的会话语义(unify-agent-session-id),压缩暴露面(compaction-surface、trim-hook-snapshot-noise)。分支名本身就是意图声明——“这周删掉什么”写进了分支名。26 条分支在 10 周内出现,平均每周 2~3 条:删除是有节奏的常规动作,不是偶尔的整理。

三层机制:机器门禁、Agent 提案、决策留痕

删除能在 13,000 条 commit 的规模下不发生混乱,依赖三层机制,每层解决一个问题。

第一层解决“能不能合”:机器门禁。检测重复代码块的工具 jscpd、扫描死代码的 knip、检查包发布配置的 publint,加上按文件 100% 的测试覆盖率门槛(test:coverage 脚本),全部挂进 pnpm run 与 CI。不合规的改动无法变绿。这一层不区分代码来源,AI 写的和人写的走同一个门。

第二层解决“删什么、影响多大”:Agent 提案。仓库内有一个把简化流程化的编码代理技能 dsh-find-simplifications:先给出判定标准,再实测影响面,输出提案。代理负责找候选与测量,不直接改主干。

第三层解决“谁说了算”:决策留痕。.agents/notes/ 目录下有 2,250 条决策记录,状态机为 proposed → implemented → archived / rejected,且强制填写 Alternatives(备选方案)。

三层合起来回答了人的注意力分配问题:在 13,000 条 commit 的规模下,人不需要逐条看。人只出现在两个位置——定义门禁规则与简化判定标准;对提案做最终裁决(archived / rejected 需要人拍板)。扫描、测量、提案、实施全部由机器与代理承担。

为什么写进 prompt 的事前限制无效

事前限制与事后治理的差别有两个。

作用时间不同。prompt 约束作用于生成时刻,影响模型下一次生成的选择;膨胀是积累问题——13,147 条 commit 各自在生成时都合理,堆叠 10 周后结构才失控。生成时刻的一条约束,约束不了 13,147 次生成的合力。

可验证性不同。“做最小实现”“不要过度抽象”没有可判定的语义:没有测试能断言一段代码是否“过度抽象”,只能靠人逐条抽查,进不了 CI。事后门禁的语义可判定:重复代码块的数量、死代码导出、单文件覆盖率都有确定答案,能变成红灯绿灯,由机器逐条校验。

为什么流程比“Agent 自觉”可靠

另一种常见思路是依赖 Agent 自觉——“让它自己保持克制”。这个思路有两个缺口。

没有反馈回路。Agent 删代码后,如果删错没有被拦截,错误不会回到 Agent 那里,它也没有理由在下次更谨慎。第一层门禁补上了回路:删错导致测试变红,错误回到提案环节。克制与否取决于反馈回路是否存在,而不是 Agent 的态度。

判断与执行没有分离。dsh-find-simplifications 把“什么是简化”(判定标准)与“怎么找简化”(扫描与实测)分开:代理执行与测量,人判断与裁决。如果标准、执行、验收由同一个 Agent 完成,判断就没有外部锚点。提案状态机保证每条决策有明确的裁决者,而裁决者不参与执行。

重构成本为什么现在可以承受

“重构有风险”长期劝退删除。DSH 用三件事把风险降到了可承受范围。

机器验证网兜底删错。删除最大的风险是删掉还在用的行为。按文件 100% 的覆盖率加上 CI 门禁,行为一旦被改坏,测试立刻变红。删错的发现时点从“上线之后”提前到“提交之时”。

并行扫描摊薄时间。45% 的 Merge 占比说明这个仓库本身就在高频并行合并;26 条 simp 分支可以同时扫描不同模块,互不阻塞,由合并统一消化。

删除范围有界。两条示例重构分别涉及 54 和 68 个文件,但都是单一主题。一次只动一个模块,红了就回滚该分支——这也解释了 revert 为何只有 36 条:改动足够小,不需要整体回退。

落地清单:五步起步

这套机制不需要 13,000 条 commit 的规模才值得用。最小起步五步:

  1. 挂机器门禁:检测重复代码的工具(如 jscpd)与扫描死代码的工具(如 knip),接入 CI(命令见附录)。
  2. 让门禁真的拦:坏味道不修就不绿。只警告不拦截,不产生反馈回路。
  3. 建提案通道:一次一个主题、一个分支一条提案,写明改动行数、文件数与行为影响。
  4. 留决策记录:一个 notes 目录,四态状态机,强制 Alternatives。
  5. 把找简化变成固定节奏:把判定标准与影响测量写死成流程,按周期执行,而不是等“有时间再说”。

边界与适用条件

本文证据全部来自 DSH 的公开 commit 史与仓库结构分析,没有运行其代码,也不构成对代码质量的评判。结论适用有三点边界。

治理强度匹配参与度。DSH 是高频并行开发的开源仓库;个人项目或低频率项目只需要第一步的门禁。2,250 条决策记录是配套规模,不是起步规模。

复杂度指标只提示、不进 gate。DSH 门禁选的都是有确定语义的指标(重复、死代码、覆盖率)。圈复杂度一类指标给的是信号不是判决,放进 gate 会产生噪音。

删除前先问三句:还有没有调用方(死代码扫描回答);删除后的行为变化能否被测试覆盖(覆盖率回答);这段逻辑是否只有这一处知道(重复语义是否成立,由 jscpd 加人判断)。三句都有答案再删。

未验证项:13,147 是 commit 条数而非代码行数,本分析没有统计行数净变化;提交类型按主题首词归类,分支内实际改动未逐条核验;“AI 参与开发”是从 codex/ 前缀、.agents/ 目录与技能命名推断,仓库未逐条标注作者。

附录:复用命令与 DSH 统计命令

在自己的项目里复用的最小命令集:

npx jscpd src        # 重复代码检测
npx knip             # 死代码与未使用导出
npx publint          # 包发布配置检查

覆盖率按文件设 100%:在测试运行器(如 vitest / jest)的覆盖率配置里把每文件阈值设为 100%,并接入 CI。

DSH 公开 commit 史的可复现统计(数字对应 2026-08-21 的仓库状态;仓库此后继续演进的话,clone 结果会略大于文中数字):

git clone https://github.com/deepseek-ai/deepseek-harness
cd deepseek-harness

git log --oneline | wc -l                          # 13,147
git log --oneline | grep -c "^Merge"               # 5,891
git log --oneline | grep -cE "^fix"                # 2,490
git log --oneline | grep -cE "^docs"               # 1,435
git log --oneline | grep -cE "^test"               # 1,028
git log --oneline | grep -cE "^feat"               # 745
git log --oneline | grep -cE "^refactor"           # 494
git log --oneline | grep -ci "revert"              # 36
git log --oneline | grep -oE "codex/simp-[a-z0-9-]+" | sort -u | wc -l   # 26

说明:以上按 commit 主题计数;grep -ci revert 统计的是主题中含 revert 的提交,36 为其数量。refactor 示例的逐条行数可用 git show <commit> --stat 核对。