你的 AI 助手是收到了通知,还是只背了锅?

HN LLM Code Research 2026-09-16T06:03:25.093558

2026-08-14 · 5 分钟阅读 · 更新于 2026-09-15

我以为自己给几个 AI 编程助手定下过一条规则:「别把另一个助手干的活带进你的提交里。」这条规则写进了我的决策台账(DECISIONS.md)——一个专门存放我和助手们共同遵守的裁定文件。67 分钟后,一次提交还是带上了另一个助手的改动。这些助手其实是同一个编程工具里的几段独立对话,我允许它们执行 Git 命令,不必每次都找我批准,有时它们还会在同一批文件上干活。但在怪它们之前,有件挺基础的事得先确认:我到底有没有把这条规则写进 CLAUDE.md 和 MEMORY.md?这两个文件会在每次对话开始时自动作为指令加载。

我把它留在哪儿了

和助手的多段对话(也就是多个会话)可能同时操作同一份检出。就在同一天的早些时候,我还没提交这条规则之前,有一次提交已经带进了另一个会话负责的内容生成流水线中的五个文件,而提交信息里对此只字未提。文件是留下来了,但说明它们为什么该在那儿的解释没有。

这条规则要求暂存时必须写明具体路径。像 git add -A 这种一把全收的命令,被排除在外。

以下是助手替我做的两次提交,时间是 Git 里的本地时间:

18:57  提交规则:暂存时写明具体路径。
20:04  提交内容包含 Git 钩子文件里的三行外来代码。

两个时间相差 67 分钟。后一次提交的暂存命令没有记录下来,所以我没法断定它用了 git add -A。不过 diff 里确实出现了那三行外来代码——是标明生成的钩子版本的注释。写下它们的那个会话,当时也看到有人在同一个检出里干活,可它还是往那儿写了。

第二天早上的分析报告检查了指令文件 CLAUDE.md 和记忆索引 MEMORY.md——这两个文件都会在对话开始时加载。结果发现,那条暂存规则只存在于台账和一段脚本注释里,在每次新对话都会加载的这两个文件中根本没有。

那是我的错。我记录了决定,却没有把指令发出去。新的对话没有收到任何新东西。助手可能单独打开过账本;但记录无法证明 20:04 的提交者是否也打开过。它当然也不能证明对方抗命。

什么能拒绝它?

把规则放进已加载的指令里,助手仍然要负责遵守它。我希望尝试执行一条宽泛的暂存命令时会失败。助手软件自带的拒绝列表是最先该试的地方,但一条记录在账本里的测试发现,在我使用的权限绕过模式下,它并不生效。

有一种在工具调用前运行的钩子,可以在那种模式下拒绝该调用。这个钩子属于助手软件;那些带时间戳的文件属于 Git。钩子的防护脚本会检查命令,并向助手返回拒绝。这个检查是在我提交那条规则后的第二天加进去的。

五周后,它的测试套件通过了这些检查:

最后一项检查很重要。我需要能够写一条关于 git add -A 的提交信息,同时不会因此被阻止提交针对它的检查。防护脚本只把处在命令位置的该命令认出来;提到它的名字是允许的。

那个测试表明,拒绝是有效的。但它没法告诉我它避免了多少错误。在那五周里,这条规则没有记录下任何东西。它最早记录的三次拒绝,最有可能来自一次故意触发防护脚本的测试;日志分不清测试和疏忽。我拿不出可量化的减少数据来报告。

一个模型对我一个月的决策账本、记忆文件和跨项目审计做了分析,发现有七个修复只停留在文档里,其中六个在之后又出现了同样的问题。而在七个带有阻断性检查的修复中,没有一个在它们原本要拦下的命令上失败。它确实找到的失败,用的是没有任何检查点名的命令。它还提醒说,一个不到三天的修复还没有经过时间的检验。

  • 一条规则需要有地方抵达,也需要有东西能说不。

现在这两样我都能指认出来了。但确切地说,我到底让什么变得不可能了?

你没写的那次提交

我定下这条规则十六天后,有个会话暂存了十三个明确的路径。它守规矩了。可还没等它提交,另一个会话就用自己写的提交信息把这些改动提交了。

你挑了哪些文件,管不住下一个提交的人。每个工作区只有一个索引,也就是暂存区。一条普通的 git commit 会把里面的东西全部提交,不管是谁放进去的。

用一个 shell 依次扮演两个会话,就能看到这件事。我在一个临时父目录下的全新目录里跑了下面这些命令,不在自己的仓库里:

git init -q one-tree && cd one-tree
git commit -q --allow-empty -m 'start'
printf 'mine\n' > mine.txt
printf 'yours\n' > yours.txt
git add mine.txt                    # session A
git add yours.txt                   # session B
git commit -q -m 'B: add yours.txt' # session B
git show --stat --format='%s' HEAD

实际输出把提交信息里漏掉的工作点了出来:

B: add yours.txt

mine.txt  | 1 +
 yours.txt | 1 +
 2 files changed, 2 insertions(+)

两个会话都没有大范围暂存。想限制提交本身,可以用 -o,也就是 --only,指定具体路径。在两个文件都已修改并暂存的情况下:

printf 'mine 2\n' > mine.txt
printf 'yours 2\n' > yours.txt
git add mine.txt yours.txt
git commit -q -o yours.txt -m 'B: yours.txt only'
git show --stat --format='%s' HEAD
git status --short

这次我的运行结果打印出:

B: yours.txt only

yours.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
M  mine.txt

mine.txt 仍停在暂存区没提交。这个方向能保护已有的、已被跟踪的文件。但如果换成全新的文件:

printf 'new\n' > new.txt
git commit -o new.txt -m 'B: new.txt'

命令以状态码 1 退出,并打印:

error: pathspec 'new.txt' did not match any file(s) known to git

新文件必须先 add,这一下又把共享的暂存窗口打开了。现在我的自动化写入方改用一个辅助工具,给提交加锁并指定路径。而独立的助手会话之间仍然只能靠约定,十三个路径那次事故之后刚过一天,又有一个身份不明的写入方拿走了另一个会话暂存的工作。

我的检查方法管用,但仍有不少要修的地方。现在我知道下一步该测什么了。

本文总结出的模式

查看原文