Agent 协作中的提交与测试边界
太阳作者太阳
原创内容采用 CC-4.0 协议发布,转载请注明出处
AgentGit测试提交边界回归验证协作规范

Agent 协作中的提交与测试边界

代码 Agent 参与仓库修改时,最容易混在一起的两件事是提交和测试:前者决定这一轮工作怎么进入历史,后者决定哪些验证值得长期留在仓库。它们共同服务一个目标:让人能审查、复查、回滚一个完整工作单元。

如果所有改动都堆在工作区里,用户只能看到一大段混合 diff,很难判断某次 Agent 回复到底改了什么、为什么改、哪些改动属于同一个目标。如果 Agent 为了证明自己“做过验证”而沉淀大量测试,仓库又会被源码扫描、文案快照和临时调试测试拖累。提交和测试都不是越多越好;真正重要的是边界清楚。

提交边界:表达一个完整工作单元

Git 提交不只是版本记录,也是每轮 Agent 改动的审查边界。提交应该表达一个完整工作单元,而不是表达 Agent 的每一步思考过程。

合适的提交边界通常是:

  • 一个完整 bug fix,包括代码、必要测试和相关说明。
  • 一个可独立审查的功能切片。
  • 一个行为变更及其验证材料。
  • 一次调查结论或项目知识记录。
  • 一次仓库规则更新。

不适合单独提交的内容包括:

  • 临时调试代码、实验性改动或未完成方案。
  • 同一行为下的零碎文件修改,例如先提交代码、再提交同一行为的测试、再提交同一行为的说明。
  • 只因为“刚改完一个小文件”就创建的微提交。
  • 和当前工作单元强相关、应该被折叠进去的小修小补。

同一行为的代码、测试和文档通常应放在同一个提交里,因为它们共同解释“为什么这样改、如何验证”。只有当改动彼此可以独立理解、独立回滚时,才应该拆成多个提交,例如互不相关的 app、互不相关的功能、机械格式化和实际行为变更分离,或一篇不属于本次代码交付的项目知识文档。

提交身份:不要冒用用户身份

Agent 提交不能默认使用用户的 Git 身份。比较稳妥的做法是在提交命令里显式指定 Agent 身份,不修改用户的全局 Git 配置,也不要求长期写入仓库本地配置:

git -c user.name="AGENT_NAME" -c user.email="AGENT_EMAIL" commit -m "message"

这里的用户名和邮箱可以换成团队约定的 Agent 身份。重点是提交身份要明确表达“这是 Agent 提交”,不要冒用用户身份,也不要覆盖用户自己的 Git 配置。

在 GitHub 上,commit 是否显示成某个账号,取决于提交邮箱是否关联到对应 GitHub 用户。如果邮箱没有被任何账号验证,GitHub 仍会显示提交里的名字,但头像通常是未关联状态。也就是说,AGENT_NAME <AGENT_EMAIL> 这种身份能表达角色,但不会自动变成一个带头像、可点击的官方身份。

如果团队希望 Agent 在 GitHub 上有稳定头像和可点击身份,比较稳妥的做法是创建或指定一个项目 bot 账号,并使用该账号验证过的邮箱,或 GitHub 分配的 users.noreply.github.com 地址。不要随手编一个看起来像官方组织的邮箱,因为这只会改变提交文本,不会获得 GitHub 账号归属,也容易造成来源误解。

可以用下面的命令确认最近一次提交实际使用的身份:

git show --format=fuller --no-patch HEAD

如果最近一次提交误用了用户身份,并且还没有推送,或用户明确允许重写最近提交,可以用指定身份的方式重写最近一次提交:

git -c user.name="AGENT_NAME" -c user.email="AGENT_EMAIL" commit --amend --no-edit --reset-author

重写后提交哈希会变化,因为 Git 提交对象包含作者、提交者和时间等元数据。已经推送到共享分支的提交不要由 Agent 擅自重写。

提交动作:需要明确触发

Agent 需要主动判断提交边界,但不应该把“边界清楚”自动理解成“可以立刻提交”。提交动作需要有明确触发,常见触发包括:

  • 用户明确说“提交一下”。
  • 当前任务一开始就约定了完成后提交。
  • 仓库或团队规则明确允许该类工作自动提交。

如果用户明确要求“提交一下”,通常可以视为代码范围和验证已经确认。Agent 不需要固定重新跑完整 git status、完整 diff、log 或 show 来重新审查;只需要为当前相关改动命名、stage、commit。如果用户已经给出范围,就按范围提交。

只有在无法判断应提交哪些文件,或用户提示存在无关改动时,才做一次最小必要确认,例如限定路径的:

git status --short -- <path>

这个规则的重点是减少无意义的反复确认,但不是放松边界。Agent 仍然不能 stage、revert、commit 用户未说明的无关改动。

如果修改还没完成,但 Agent 需要区分“已经确认的部分”和“继续试验的部分”,不应该靠提前提交来制造对比点。Git 暂存区本来就应该承担这个角色:

git add <path>
git diff --cached

暂存区表示“当前认可的候选提交”,工作区表示“还在斟酌的改动”。如果后续判断发现提交边界要调整,可以重新 git restore --staged &lt;path&gt; 或重新 git add &lt;path&gt;,而不是多创建几个临时提交。

测试边界:只保留能防回归的验证

Agent 在修 bug 或实现功能时,容易把“我需要证明自己做过验证”误写成大量测试。测试本身不是越多越好;如果测试锁住的是实现形态、源码字符串或临时判断,它会让项目看起来更安全,实际上只是增加维护噪音。

值得进入仓库的测试通常有几个特征:

  • 覆盖安全或权限边界,例如授权 token 的签名、过期时间、机器绑定和 feature 列表。
  • 覆盖外部配置格式,例如读取和写入浏览器配置文件。
  • 覆盖真实文件操作边界,例如导入压缩包、整理解压目录、避免覆盖或污染用户数据。
  • 覆盖运行时不容易安全发现的问题,而不是普通业务页面一跑就能看出来的问题。
  • 能用稳定输入直接验证输出,不依赖当前源码长什么样。

这些测试的价值在于:当未来 Agent 或开发者改代码时,它们能阻止真实行为倒退。

不要把临时验证沉淀成仓库噪音

不应该因为“写过验证”就把所有测试留下来。几类测试尤其容易变成噪音:

  • 源码扫描测试:读取 .ts 文件内容,然后断言某些函数名、字符串或变量名存在/不存在。这类测试测的是实现形态,不是行为。
  • 文案快照测试:把一整组 UI label 固定下来,只要改文案就失败。如果文案不是业务协议,这类测试通常不值。
  • 内部结构测试:断言某个内部字段数组、helper 名称或渲染函数只出现一次。它们会阻止正常重构。
  • 薄 helper 测试:只覆盖一两行显而易见的包装逻辑、事件转发、尺寸计算或布尔判断。除非这类 helper 曾经造成真实事故,否则通常不值得单独留测试。
  • 业务内部状态测试:在业务应用里,流程步骤、普通输入解析、状态序列化/反序列化通常应通过实际运行和人工验收发现问题,而不是像公共类库一样逐个 helper 写单测。
  • 临时调试测试:为了证明一次排查路径写下的测试,排查结束后没有长期价值。
  • 没有接入验证链路的测试:如果测试不在 check 或 CI 中运行,就只是仓库里的负担。

判断标准可以很直接:这个测试失败时,是否说明授权边界、外部配置文件、真实文件操作或难以靠运行时安全发现的迁移逻辑真的出问题了?如果不是,就应该删掉,或者改成一次性的实际运行验收。

测试名称也应当服务于阅读者。中文项目和中文使用者优先使用中文测试名;保留英文只适合协议字段、API 名称、错误原文等必须精确引用的内容。

提交和测试要对齐

提交边界和测试边界应该相互解释。一个行为变更如果值得提交,通常也应该说明它靠什么验证;一个测试如果值得保留,通常也应该能解释它保护了哪个提交里的行为边界。

这不等于每个提交都必须新增测试。文案、样式、内容整理或配置小改动,可能只需要人工检查或轻量验证。相反,权限、安全、文件写入、迁移、外部配置解析这类边界,即使改动很小,也值得有可复跑的回归测试。

比较好的做法是:

  • 提交信息描述行为边界,而不是文件名。
  • 测试名称描述要防止的回归,而不是实现细节。
  • 验证命令接入常用检查链路,否则测试容易变成无人运行的仓库负担。
  • 如果测试只是为了辅助一次排查,排查结束后要么删除,要么改成真正的回归测试。

协作约定

团队可以把这套规则写进自己的协作说明里:Agent 需要判断提交边界,但提交动作需要用户明确要求或已有约定;用户要求提交时,不要固定重新审查完整工作区,只做当前相关改动的命名、暂存和提交。

这个约定的重点不是让 Agent 频繁提交,也不是让 Agent 为了证明自己做过事而留下大量测试。提交应该让工作单元可审查,测试应该让关键行为可回归。两者都服务于同一件事:让人和 Agent 的协作结果可理解、可验证、可维护。