TB 三模实测

避坑实验室 · run-002 · 样本量 n = 1

同一个隐形字符 bug,三个 AI 都修对了——差在谁的 diff 更干净

如果你用 Windows 记事本保存过 .env,第一行配置前面可能会多一个看不见的字符;程序不报错,但 API_KEY 就是查不到。 我们让 Codex、Claude Code、Gemini CLI 同题修复,外加它们看不到的隐藏验收。
上期看谁修得快,这期看谁收尾干净。

先讲人话:这个 bug 是什么

你在 Windows 记事本里编辑过 .env 配置文件吗?保存时它可能悄悄在文件最前面塞了 3 个字节—— 一个叫 BOM 的标记,你可以把它理解成某些编辑器写在文件开头的编码提示。它完全不可见,但程序读配置时,第一个变量名就从 API_KEY 变成了 \ufeffAPI_KEY——前面那个 \ufeff 就是隐形字符的学名。

于是:不报错、不崩溃,但你的程序死活读不到 API_KEY。新手能被这种问题卡一整天。

EFBBBF46 'F'49 'I'52 'R'53 'S'54 'T'3D '='

红色那 3 个字节就是 BOM——肉眼在编辑器里根本看不到它。这是常见 Python 第三方配置库 python-dotenv 的真实 bug(上游 PR #640)。

实验怎么做

1

同一起点
固定在官方修复之前的 commit
fa4e6a90

2

同一段指令
三家收到逐字相同的任务描述

3

隐藏验收
它们看不到的 5 项隐藏验收,修完才揭晓

记分牌

下面只记录这一次任务里的交付差异,不代表三家工具综合能力。

Codex

隐藏验收 ✓
用时1分47秒最快
工程卫生A自己清理了临时文件

API 层回归测试

环境里没装测试工具,它自己找到替代方案跑通,最后还把过程中生成的锁文件删干净了。

Claude Code

隐藏验收 ✓
用时2分25秒中间
工程卫生A+改动最干净

解析器层回归测试

只动了该动的两个文件,测试直接加进现有用例表,还写了注释说明为什么。

Gemini CLI

隐藏验收 ✓
用时3分27秒最慢(含一次平台重试)
工程卫生B留下了无关文件

新建独立测试文件×3用例

修对了,测试覆盖也最广,但 diff 里混进了一个无关的依赖锁文件和多余空格。

用时为操作者实测的本地 CLI 墙钟时间,非标准化算力基准。Gemini 含一次「429 无可用容量」平台重试。

有意思的地方:三家改的是同一行代码

核心修复一模一样——读文件时,开头如果是那个隐形字符,掐掉它:

class Reader:
    def __init__(self, stream: IO[str]) -> None:
        self.string = stream.read()
+       if self.string.startswith("\ufeff"):
+           self.string = self.string[1:]
        self.position = Position.start()

真正拉开差距的,是 diff 里的收尾动作。 Claude Code 把回归测试加进现有用例表、附注释;Codex 在 API 层测、顺手清理了临时文件; Gemini 单开一个测试文件覆盖 3 种用法——但把一个无关的 uv.lock 也提交了进来。

收尾检查CodexClaude CodeGemini CLI
核心修复正确
带回归测试✅ 覆盖 3 种入口
diff 只含相关改动⚠️ 混入 uv.lock
无格式噪音⚠️ 尾随空格
临时文件清理✅ 主动删掉—(没产生)❌ 留下了

隐藏验收长什么样

修复完成后,我们做了 5 项隐藏验收。先看最容易理解的 3 个 BOM 行为用例:

  1. 带 BOM 的单变量文件 —— 必须解析出干净的 FIRST,禁止出现带隐形前缀的键
  2. 带 BOM 的多变量文件 —— 第二行之后的变量不能受影响
  3. 不带 BOM 的正常文件 —— 防止「修过头」破坏原有行为

另外两项是 Unicode 值保留parser 测试套件——防止修复误删正常 Unicode 字符,或破坏现有解析行为。

三家全过、5 项全过。这轮没有翻车故事——但正因为都修对了,「干净程度」才成了真正的分水岭。

这期的结论

代码能跑 ≠ 能直接合进项目。

三个 AI 都能把活干对,但「干不干净」决定了你敢不敢不看一眼就合并。 如果你只记一件事:AI 说"修好了"之后,看一眼它的 diff 里有没有混进无关文件。 发布前多看一眼 diff,通常比事后回滚便宜得多。

证据与复现

  • 真实仓库:theskumar/python-dotenv,起点 pin fa4e6a90b45428212452afc6ee0d5c8103b9301d(官方修复 PR #640 之前)
  • 三家完整 diff、隐藏验收用例、运行时间线:见上文与 方法论 v1
  • 原始终端日志已完整存档,复现或索取请走 GitHub issue

单任务 n=1,本文不构成三家工具的综合排名。每期任务都会换,结论只对本任务负责。上一期:run-001 · 同一个 bug,三个 agent,一个隐藏测试