安全智能体如何跨过那行它“看不见”的注释,升级了被固定的依赖
一位西班牙客户投诉称,她的年度续费被提前一天计费了。支持工单在经历了三个队列后,终于转到了一位工程师面前,他敏锐地察觉到了问题的端倪:这是一个日期格式化的回归(regression)问题,且仅出现在欧洲用户群中。他在 date-formatting 模块上运行了 git log,却一无所获。该模块已经 11 天没动过了。而 11 天前真正被改动的,是它的 package.json —— lodash 的版本从 4.17.20 升级到了 4.17.22。这次升级是由一个安全代理(security agent)发起的,由值班人员批准,并在没有任何评论的情况下合并了。
在同一个文件中,版本字符串上方两行有一条 18 个月前写的注释:// do not upgrade — breaks the snapshot tests in date-formatting, see FRONT-2418(请勿升级 —— 会破坏 date-formatting 中的快照测试,详见 FRONT-2418)。安全代理没有阅读它。或者更准确地说:安全代理阅读了整个文件,但它的提示词(prompt)指令是查找有漏洞的版本字符串,而 不是衡量周围注释的权重。这条注释是承载关键信息的机构知识(institutional knowledge)。而代理却将其视为无关紧要的背景装饰。
这是一个两个互不知晓正在发生碰撞的系统之间的协同失效。安全代理履行了它的职责。写下注释的原工程师履行了他的职责。每次修改文件都遵守固定(pin)版本的开发代理也履行了它的职责。唯独没有人决定谁该负责在它们之间进行调解。
两个代理,一个仓库,没有协议
该团队的配置按照 2026 年的标准来看并无特别之处。安全策略代理按计划每晚运行,扫描依赖图中的已知 CVE,并提交 PR 以升级版本。功能开发代理每天早晨处理 Jira 工单,创建一个分支,并针对工单涉及的包提交 PR。两个代理读取同一个事实来源 —— 代码仓库 —— 并且都通过相同的拉取请求(PR)机制进行写入。
它们所不共享的是对彼此前置条件的任何认知。安全代理的提示词编码了一个单一目标:升级有漏洞的依赖。功能代理的提示词编码了另一个目标:实现工单功能。两个提示词都没有提到另一个代理。两个代理都没有读过另一个代理的提示词。每个代理的规划器(planner)在查看代码库时,都仿佛自己是唯一的编写者。
版本控制擅长检测两个编写者修改了同一行。它不擅长检测两个编写者出于互不兼容的原因修改了不同的行。安全代理和功能代理从未产生过合并冲突,因为它们很少在同一天针对同一个包提交 PR。碰撞发生在一个更缓慢的维度 —— 跨越数周 ,跨越多个 PR,针对那些两个代理都没有被训练去遵守的、存在于注释中的共享机构知识。
复盘后的架构认知是:在多代理操作下的代码库是一个多写系统(multi-writer system),其冲突解决取决于每个代理的提示词恰好编码了什么。这里没有共享锁,没有协商。哪个代理先运行,它就写入了其他代理所继承的状态。
注释不是文档,而是契约
在 18 个月前的原始 PR 中,查看固定 4.17.20 行的审阅者写下了那条注释,因为他花了四天时间在欧洲语言环境的快照测试中排查一个日期偏移一天的 bug。他将回归问题锁定在 lodash 的 _.isDate 与团队使用的区域感知日期解析器交互的具体变化上。他将版本降级到了 4.17.20,在注释中记录了原因,提交了工单 FRONT-2418,并发布了修复。这条注释是代码中唯一保存该知识的地方。工单是纯文本中唯一保存该知识的地方。两者通过一个安全代理提示词无法解析的字符串链接在一起。
这种模式很常见,但被低估了。固定版本旁边的注释不是关于代码的评注 —— 它们是解释代码为何如此而非彼样的契约(contract)。它们以压缩的形式编码了之前的事故。当一个代理(或人类)在不阅读注释的情况下升级固定版本时,它不只是丢失了上下文,它覆盖了团队在代理存在之前做出的决定。
安全代理的提示词本可以包含一条指令:阅读固定版本附近的注释,并将任何非空注释作为前置条件而非背景进行提级(escalate)。但它没有。团队 在构建代理时假设固定版本要么是出于历史审慎(可以安全升级),要么是活跃风险(CVE),并没有“由于文档记录的原因而固定”这第三个类别。而在任何成熟的代码库中,这第三个类别是三者中规模最大的。
当能抓到 Bug 的测试被隔离时,CI 也救不了你
PR 通过了 CI。这是团队发现最难启齿的事故部分,因为它意味着他们以为拥有的安全网其实并不存在。
date-formatting 模块的快照测试在两个月前被隔离(quarantined)了。在一次 Node 版本升级后,这些测试开始间歇性失败,团队最终确定这是测试运行器中的时区处理变化。修复本需耗时一天。但当时正值季度中期,少了两位工程师,团队选择了阻力最小的路径:将测试套件标记为隔离,提交一个取消隔离的工单,然后继续。
当备选方案是让测试套件在每次合并时都像抛硬币一样不稳定时,隔离不稳定的测试套件是正确的做法。错误的做法是忘记了被隔离的套件是针对特定类别 bug 的回归检测器。从隔离标志开启的那一刻起,每个涉及 date-formatting 模块依赖的 PR 在其安全网中都有一个漏洞,而 CI 的绿色对勾让谁也看不见它。
- https://www.augmentcode.com/guides/how-to-run-a-multi-agent-coding-workspace
- https://mikemason.ca/writing/ai-coding-agents-jan-2026/
- https://addyosmani.com/blog/code-agent-orchestra/
- https://www.mindstudio.ai/blog/git-worktrees-parallel-ai-coding-agents
- https://docs.github.com/en/code-security/concepts/supply-chain-security/about-dependabot-security-updates
- https://charpeni.com/blog/minimizing-risk-properly-and-safely-resolving-cves-in-your-dependencies
- https://docs.renovatebot.com/dependency-pinning/
- https://www.atlassian.com/blog/atlassian-engineering/taming-test-flakiness-how-we-built-a-scalable-tool-to-detect-and-manage-flaky-tests
- https://www.minware.com/guide/best-practices/flaky-test-quarantine
- https://www.qodo.ai/blog/github-ai-code-review/
- https://www.oreilly.com/radar/conductors-to-orchestrators-the-future-of-agentic-coding/
