免责声明:AI 辅助是如何使用的
为了避免这篇报告被指责为"不过是 Claude 在替 Claude 辩护"、"AI 垃圾内容"、"可能全是幻觉"等等,我认为有必要先说明几个关键点:
所有指标、方法和数据来源均由我本人选择,并且咨询了我的妻子——她拥有宾夕法尼亚州立大学(Penn State University)统计学硕士学位。
方法论直接基于我妻子的建议:她指出,如果仅仅比较引入 Claude 前后每十行代码的 bug 数量,由于后 Claude 样本量太少,噪声会太大;同样地,试图构建线性回归模型来厘清不同变量的相对影响,可能也行不通。她明确告诉我,最好的做法是观察后 Claude 版本在历史分布中所处的位置,以及从历史分布来看,出现与后 Claude 版本"一样差或更差"的版本的概率有多大。
我花了数天时间,在创建 GitHub 仓库之前就已经投入了两天,并且根据上述我妻子的反馈,对报告进行了至少一次重大的整体重写。这背后是我大量的手动认知劳动。
用于获取数据、整理到 DuckDB 数据库中、构建数据库视图、以及进行统计分析的那些脚本,确实是由 GLM 5.1 编写的。同样,你现在看到的最终报告网页中的 HTML 和大量原始散文也是 AI 写的。
但至关重要的是:本报告中的所有数字、统计数据、卡片和图表,都是由运行统计分析的 Python 脚本自动模板化生成的,从而完全避免了数字上的幻觉或不一致的可能性。
在我将报告发布到 Hacker News 之后,几乎没有收到任何对文章实际内容的实质性反馈、讨论或回应。于是我决定用我自己的语言彻底重写所有散文部分。如果有人抱怨我啰嗦或句子结构不好——就像他们一直以来做的那样(这正是我最初让 AI 写散文的原因之一,其他原因也已被模板化替代了)——他们可以去他妈的。
如果你想复现这里的数据和结果,并仔细检查它们是如何计算的,可以访问此仓库。我有意让整个流水线可以从头到尾完全从头运行,这样你可以看到完整的端到端流程,没有任何神秘的数据库二进制文件强迫你相信我篡改或搞砸了数据。如果你对数字不满意,先去看那边。
背景:rsync 引发的众怒
2026 年 5 月下旬,rsync 炸了锅。首先,一条毫无证据的 Mastodon 帖子指向了一个虚假的相关性:某个用户升级到某个版本后遇到了回归问题,而该版本恰好包含 Claude 提交的代码。具体观看次数未知,但仅点赞和转发就轻松突破了千次,并且获得了巨大的关注——就像所有反 AI 的仇恨情绪一样——最终收到了 32 位独立用户的 58 条回复。有人毫无证据地愤怒斥责"认知投降";另一个人建议将 rsync 加入臭名昭著的 open-slopware 黑名单。从那里,风波蔓延到了 Hacker News,产生了 81 条评论,充满了恐惧、愤怒和叫嚣——终于"一劳永逸地证明了没有人能安全地使用 LLM"。其中有一条特定评论进一步加剧了"回归和 bug 都是由 Claude 引起的"这一观点。
2026 年 5 月 30 日,这场正在酝酿的愤怒最终汇聚到一个焦点上:有人在 rsync 仓库发起了一个 GitHub Issue,标题为"请不要用 Vibe 搞砸这个软件"(Please Do Not Vibe Fuck Up This Software)。附件是一张批评该项目使用 Claude 的 Mastodon 帖子的截图。仅此而已。没有 bug 报告,没有技术内容,没有真正尝试确认这种担忧是否属实或合理;只有 350 多条评论,从深思熟虑的关切到赤裸裸的骚扰(最恶劣、最不讲理、甚至充满暴力的评论大多已被删除;很少有人想到要保留它们)。
那条帖子很快升级,从"软件是免费的,不喜欢就 fork 或者滚蛋"一路发展到了"就算你在给流浪汉免费发汤,也不代表你可以在里面撒尿"。
事态并未止于言语。最终,当一位用户发布了一条现已删除的评论,其中包含 My Little Pony 风格的绘画,画中的自己正在勒死"推送了 vibe 编码提交的项目看门人"时,冲突升级到了暴力幻想画面。
一个用户发布了针对 rsync 维护者的暴力绘画——这是将 Issue 从激烈辩论升级到骚扰的威胁之一。
完成了互联网愤怒循环的最后一环,这个 Issue 又传播回了 Hacker News,又生成了数百条评论。一些人试图用引入 Claude 后回归问题的数量作为证据——"Linux Mint Timeshift 工具有一个 Issue,记录了 rsync Issues 页面上当前处于开放状态的许多回归问题,它们都是在 vibe 编码之后才引入的"——来证明情况变得更糟了。另一些人则指出,那些回归问题并非由 Claude 引起,作为回应,对方又再次移动了球门柱。如此反复,核心主题始终是同一个中心论断,在各地被反复重复:Claude 辅助开发给一个原本稳定的工具引入了 bug。AI 是认知投降,是可卡因,是手艺的丧失,用户因此愤怒是完全合理的。
人们完全有理由愤怒——一个非常稳定、备受信赖的工具,仅仅因为主要开发者在对该软件进行 vibe 编码,就开始立刻走下坡路了……
—— fao_ 在 Hacker News 上
然而,这并不一定是一个只能凭——讽刺的是——"感觉"来解决的问题。这是一个至少在一定程度上可以用经验来检验的问题。甚至有人指出了这一点:
在 Lobste.rs 上,作为对 Tridge 本人发布的 Medium 文章的回应,终于有一些用户(如 boramalper)开始真正要求从某个方向拿出证据:
如果有人能真正做一个每次发布后的回归问题时间线图(如果可能的话),看看数量最近是否真的上升了,那会很有趣。
—— boramalper 在 Lobsters 上
用户 bitshift 回复说:"我也很想看到这样一张图。它不会完全说明问题……但至少我们有了可以衡量的客观指标。"
这份分析报告就是那张图。或者说,在数据局限下(见前一节)尽可能做到最好的版本。
执行摘要
- 36 个版本具有 bug 数据,跨度从 v2.4.6 到 v3.4.3
- 2 个版本包含 Claude 提交:v3.4.2(9 个 Claude 提交,0.00 sev/10c)和 v3.4.3(28 个 Claude 提交,3.29 sev/10c)
- Claude 版本在 IQR(四分位距)的两侧:v3.4.2 低于 IQR,v3.4.3 高于 IQR。两者均非离群值。
- 精确排列检验(permutation test)p 值 = 46%:随机选取任意 2 个版本,有 46% 的概率会得到一样差或更差的结果。
- 这是可用的最强检验,结果是没有发现任何问题。
- Fisher 精确检验 p 值 = 74%:Claude 版本落在历史中位数以上的概率并不比其他版本更高(odds ratio = 1.06)。
- 历史均值是 Claude 版本均值的 1.8 倍(2.95 vs 1.65 sev/10c)
- v3.4.1(59 个 bug / 9 次提交,无 Claude)是一个离群值,但它属于基线——它是一个正式版本,分布已经将其包含了进去。
指标
本分析使用单一指标:按严重程度加权的每 10 次提交 bug 数(severity-weighted bugs per 10 commits, sev/10c)。每个 bug 的严重程度被归一化为 0–1 的分数(LLM 分配的严重程度除以 100),这些分数按版本求和,而不是简单地统计 bug 数量。原始 bug 数量也在表格中供参考,但 sev/10c 驱动了所有的统计检验。
sev/10c = (Σ severity/100 ÷ total_commits) × 10
提交如何分配到版本
默认分支上的每一次提交都按提交者日期(committer date)排序,以生成时间线序列。每个 Git 标签(tag)指向该时间线中的一个特定提交。一个版本的区间是前一个标签与其自身标签之间的所有提交。预发布标签(如 "pre"、"rc")作为边界被跳过,并合并到其最终版本中。每次提交恰好属于一个版本。
如何发现 bug 并将其分配到版本
Bug 报告来自三个来源:
- rsync 仓库中的 GitHub Issues(通过 GitHub REST API 整理)
- rsync Bugzilla 实例(通过 API 收集)
- rsync 邮件列表
GitHub Issues 和邮件列表中的 bug 归属于该 bug 被报告之前最近发布的版本。对于 Bugzilla,每条记录都有一个 Version 字段,明确声明了该 bug 是针对哪个版本报告的,因此 bug 归属于该版本。
严重程度评分
为了控制 bug 的严重程度——正如 HN 上有人所说,按钮里的拼写错误和 CVE 不应该被同等对待——每个 bug 报告都按 0–100 的尺度进行了严重程度评分。评分模型是 Qwen 3 35B,一个轻量级的开源语言模型,被提示扮演一名评估实际影响的高级可靠性工程师。每个 bug 报告的标题和正文(截断到 3,000 字符)以及以下评分标准被输入给模型:
| 分数 | 类别 | 描述 |
|---|---|---|
| 90–100 | 数据丢失/损坏 | 静默的数据损坏或数据丢失。用户的文件或备份出错,他们可能直到为时已晚才注意到。允许远程代码执行或未授权访问的安全漏洞。 |
| 70–89 | 崩溃/卡死/备份失败 | rsync 崩溃、卡死,或以导致自动化备份或 cron 任务失败的方式出错。数据未损坏但备份被遗漏。高 CPU 或内存使用率使 rsync 在生产环境中无法使用。构建或编译失败——如果 rsync 无法从源码构建,用户根本无法安装。这是一个阻塞性问题,不是小麻烦。至少评 70 分。暴露敏感数据的安全漏洞。 |
| 50–69 | 功能回归 | 功能回归——过去能用的东西不再能用了,但有变通方案。足以扰乱生产工作流的性能回归。能看到的错误输出(报错信息、错误的文件名)但不损坏数据。 |
| 30–49 | 轻微回归 | 有简单变通方案的轻微功能回归。错误信息令人困惑但操作仍然成功。偶发的测试失败。在不常见平台上的可移植性问题。 |
| 10–29 | 外观/低影响 | 外观问题、文档错误、轻微的用户体验问题。不影响用户的测试相关问题。 |
| 0 | 功能请求 | 如果 Issue 是在请求新功能、更改默认行为或提出打包建议——无论多么合理——它都不是 bug。评 0 分。 |
| 0–9 | 不是真实的 bug | 垃圾信息、无关内容、重复内容。明显与 rsync 无关或为空/无意义的 Issue。 |
所有三个 bug 来源——GitHub Issues、Bugzilla 和 rsync 邮件列表——都进行了评分。Bugzilla 和邮件列表报告只有标题(没有正文),因此模型仅根据标题评分。模型被指示在正文信息不足时依据标题,并倾向于评分范围的中段(40–60)。模型还被要求仅通过结构化输出(JSON schema)输出一个严重程度整数,因此没有需要解析的自由文本回答。评分在 temperature=0 下进行以保证确定性——相同的输入始终产生相同的分数。
严重程度评分为 0 的 Issue——功能请求、垃圾信息、关于 AI 的无关 rant、空提交——默认被排除在 bug 计数之外。这一点很重要,因为某些版本在 GitHub 上吸引了大量噪声。例如 v3.4.2 有四个 Issue 被提交;模型将所有四个都评为严重程度 0(一个功能请求选项、一个关于缺失 tarball 的提问、以及另外两个功能请求)。
数据库中各等级的示例评分:
| 分数 | 版本 | 标题 |
|---|---|---|
| 95 | v3.4.1 | Destination --chmod and --fake-super: chmod applied to fake-super, backup permissions lost |
| 75 | v3.4.3 | error in rsync protocol data stream (code 12) at token.c(490) [sender=3.4.3] |
| 55 | v3.4.1 | --dry-run does not work with --mkpath when copying files |
| 35 | v3.4.1 | manpages not installed in out-of-tree builds |
| 15 | v3.4.1 | Minor inconsistencies in options in manpage |
| 0 | v3.4.3 | PAM Support - Open for Discussion |
为什么以版本为分析单位
为什么将提交按版本分组、bug 按版本分组,然后通过版本的中间媒介来确定 Claude 提交与 bug 之间是否存在相关性?这有两个原因。
第一,因为批评者提出的论断本身也是以版本为单位的:他们认为,只要一个版本中含有任何 Claude 提交,就会使整个版本作为一个整体明显变得更 buggy——而不仅仅是说 Claude 撰写的提交可能引入了更多 bug。后者是一个不同的指标,因为在同一个版本中,后续的 Claude 或人工提交可能会纠正那些 bug,最终用户不会在发布时注意到,整体上对用户也无影响。此外,正如在其他地方所说,在批评者的论据所在层面上回应他们是很重要的。如果这迫使他们让论据更加精细——或者再次移动球门柱——那么使命就已经完成了。
第二,这是一个归因问题:绝大多数 bug 并不会明确指出是哪个具体的提交导致的,因为这样做需要进行大量的研究和分析,而相比简单地向前修复,这通常不值得。即使进行了这样的分析——比如通过 git bisect——也不一定能得出有用的结论,甚至可能什么结论也得不出。许多 bug 可能源于多次提交的组合,这些提交在时间上往往相隔甚远,很难说究竟是哪一次提交真正引入了 bug。或者,一次提交可能同时暴露出其他提交引入的几个潜在 bug,等等。
为什么是 bug 和提交?
批评者的论断是简单化的、绝对的、普遍化的:暴露于 Claude 的版本中 bug 率上升了。因此,最诚实的简单回应就是分析他们确切声称的内容:bug、提交、版本、以及暴露于 Claude 的提交。如果 Claude 版本恰好处于历史分布的中间位置,那么举证责任就转移到了批评者身上——他们需要解释为什么这个中间位置比以前的所有中间位置更糟糕。即使通过按严重程度加权,我也觉得自己在这一点上对反 AI 一方给出了极大的宽容;但既然有足够多更聪明的批评者提出了这一点,我认为这是值得的。
即使最终的结果只是将对话转向对版本中 bug 的质量、类型和用户影响进行更细致的讨论,那对于支持 AI 的一方来说也算是一个重大胜利,而对于反 AI 的一方则是一次球门柱的移动。然后我们可以在此基础上做进一步的分析。这场游戏的球在反 AI 一方的场地上。
这种方法没有做到的事
我清楚这个指标没有控制提交复杂度或安全强度。它是一个粗糙的工具。但批评者的指控同样粗糙:"Claude 把事情搞得更糟了。"我们需要用粗糙的工具来回应。血债血偿。
结果
Claude 版本
在我们深入分析之前,先直接看看这两个 Claude 版本本身,感受一下:
- v3.4.2 — 0.00 sev/10c · 0 个 bug · 50 次提交 · 9 个 Claude 提交 · 第 0 百分位(在 35 个版本中排名 0)
- v3.4.3 — 3.29 sev/10c · 17 个 bug · 34 次提交 · 28 个 Claude 提交 · 第 77 百分位(在 35 个版本中排名 27)
如果这在你看来看起来不像一个危险信号,那你是对的。
精确排列检验(Exact Permutation Test)
所以问题是:Claude 版本是否异常地 buggy?还是说,仅仅因为运气不好,你就能轻易从历史分布中抽到一样差的一组版本?在统计学上回答这个问题的方法是精确排列检验(exact permutation test),它枚举所有两两版本的组合,并问:其中有多大比例的版本组合的平均 bug 率等于或比我们实际观察到的更差?这个比例就是检验假设的 p 值。
46%
精确排列检验 p 值(单侧,H₁: Claude 平均值 > 历史平均值)
在 595 组可能的历史版本两两组合中,有 272 组的平均 sev/10c ≥ 1.65。接近一半。Claude 版本恰好位于排列分布的中间位置——它们毫无极端之处。
检验统计量:每组平均 sev/10c · Claude 组平均值:1.65 · 历史平均值:2.95
这个 p 值告诉我们,"Claude 让版本变得更糟"这一假设,至少到目前为止,其预测能力大约相当于抛硬币:如果你闭上眼睛随机选取 2 个版本,有接近一半的概率你会得到同样差或更差的结果。Claude 组并没有什么异常之处。
Fisher 精确检验(Fisher's Exact Test)
排列检验问的是:随机一组版本与 Claude 组一样差的可能性有多大?但还有另一种提问方式:Claude 版本是否比非 Claude 版本更有可能落在历史中位数以上?这是一个教科书式的 2×2 列联表,标准检验方法是 Fisher 精确检验(Fisher's exact test)。
| ≤ 中位数 | > 中位数 | |
|---|---|---|
| 非 Claude | 18 | 17 |
| Claude | 1 | 1 |
74%
单侧 p 值(H₁: Claude 更有可能高于中位数)
Fisher 精确检验问的是:如果将所有版本按历史中位数(0.74 sev/10c)分割,这些 Claude 版本是否显著地比以前的版本更 buggy(更有可能落于中位数以上)?p 值为 74%,答案是一个决定性的"不"。
优势比(odds ratio):1.06——基本上就是 1:1。Claude 版本落在中位数以上的概率与其他任何版本并无不同。
优势比:1.06 · 中位数:0.74 sev/10c