跳到主要內容

【2026 最新】Edit Fidelity 是什麼?10 個一行 Bug 測 Claude Code/Codex 有沒有改太多

最後更新: ·
Edit Fidelity AI 教學首圖,以一行正確修補與多行無關變更對照 Claude Code、Codex 的 patch 範圍閘門

Edit Fidelity 是一把專門量「Coding Agent 有沒有改太多」的尺。Claude Code、Codex 或其他 Agent 就算讓測試變綠,也可能順手重排資料流、加防禦邏輯、改格式,甚至碰到設定檔。這些 patch 不一定錯,卻會擴大 code review 與回歸範圍。

這篇帶你建立 10 個「已知只需一行修好」的 Python Bug,保存 gold patch,比較一般修正 Prompt 與 preservation clause,最後把測試、變更範圍與 excess edit distance 接成 PR 收據。範例可套到 Claude Code/Codex,但比較單位永遠是模型+Agent harness+Prompt+工具權限+版本,不是只看品牌名稱。

證據邊界:AlphaLab 檢查了論文、400 題公開資料與固定 commit,並執行本文教學版 scorer 的單元測試;沒有花費 API 額度替 Claude Code 或 Codex 跑 10 題,所以本文不提供本站模型排名。論文數字均是作者在特定函式級 Python 任務上的報告,不能直接外推到大型 production repo。

一句話重點:Edit Fidelity = 修對(tests pass)+只改必要範圍(preserve)。前者不能替代後者。

先說結論:Edit Fidelity 不是「diff 越小越好」

最小 diff 不是最高原則,符合行為契約才是。合理的替代修法可能和 gold patch 不同;過短 patch 也可能只是硬編答案。實務順序應是:先驗證指定錯誤與完整回歸測試,再阻擋越界檔案,最後才用行數、token 距離與複雜度判讀 review 成本。

Edit Fidelity 兩把尺示意圖:功能測試判斷修對,scope 與 edit distance 判斷是否只改必要範圍
Tests 回答「修好了嗎」;Scope、Locality 與 Distance 回答「是否保留了不該動的程式碼」。

When Models Edit Too Much 作者把 edit fidelity 視為獨立品質軸,而非單一總分。研究從 400 個 BigCodeBench Python 函式注入一至兩個局部 AST 錯誤;公開資料有 232 題單一 mutation、168 題兩個 mutation,共 568 次 mutation、12 個實際出現的家族。所有已知 intended reversal 都只改一至兩條正規化程式碼行。

研究在「已通過測試的修補」上比較三件事:Pass@1、超額 token Levenshtein 距離,以及相對 gold 增加的 cognitive complexity。三位資深開發者對 100 組盲測 patch 的多數判斷中,excess distance 對 reviewability 與 faithfulness 的一致率分別是 94.8% 與 96.9%;但另一批 100 個高超額案例仍有 17 個屬於有效替代修法。它是好警報器,不是自動判決。

Edit Fidelity 怎麼算?先把三個版本固定

C 是故障版、G 是已知 intended gold reversal、M 是 Agent 修正版。論文先移除註解與純格式差異、抽出函式本體,再以較長 token 序列作分母計算正規化距離 d(X,Y)

gold_distance  = d(G, C)
model_distance = d(M, C)
excess_edit_distance = model_distance - gold_distance

excess > 0 代表候選比已知 gold 改得更多;0 只代表距離相同,不保證語意相同;負值也可能是有效、更短的替代修法。複雜度則看 CC(M) - CC(G)。完整 tokenization 與 AST 正規化請看固定 commit 的研究實作;不要把 GitHub 的 additions+deletions 冒充論文指標。

步驟一:做 10 個一行 Bug,而不是挑 10 個隨機 issue

每題建立獨立 fixture,目標函式維持約 10–25 行,只有一個已知一行修補。Prompt 只寫行為契約,不透露行號;公開一個 symptom test,另放 6–12 個 hidden contract tests。故障版必須先紅,gold 套用後必須通過 hidden tests、type check、lint 與完整 regression。

Edit Fidelity 十題一行 Bug fixture:比較、range、排序、累加、算術、guard、index、函式、copy 與 slice
十題刻意橫跨 predicate、computation、boundary 與 API semantics;每題只有一個已知一行修補,但仍允許人工判定有效替代解。
  1. 比較邊界:age > 18 改回 age >= 18,測 17/18/19。
  2. range 尾端:range(len(xs)-1) 改回 range(len(xs)),守住最後一項。
  3. 排序方向:reverse=True 改回 False,同分項也要穩定。
  4. 累加初值:total = 1 改回 0,涵蓋空集合與負數。
  5. 算術運算:price + discount 改回減法,測零與小數。
  6. 空值 guard:反轉一個 if not items 條件,測空與非空輸入。
  7. list index:parts[1] 改回 parts[0],測單項與多項。
  8. 函式替換:max(values) 改回 min(values),測重複值。
  9. copy semantics:把被移除的 .copy() 加回,驗證原輸入未被修改。
  10. slice 邊界:items[2:] 改回 items[1:],守住首尾與空輸入。

另外放入 tests/、lockfile、設定檔與 generated 目錄的 sentinel hash。它們不計入 source edit distance,但任何未授權變更都算 scope violation。想先整理 Agent 的 repo 規則,可搭配AGENTS.md 規則與 Gate;大型 repo 的上下文治理則可看Claude Code 大型 Repo 安全重構

步驟二:保存 manifest 與 gold patch,先測評分器

不要讓 Agent 看見 gold patch 或 hidden tests。把它們放在 writable worktree 外,由 runner 在 Agent 結束後套用。每題 manifest 至少鎖住 baseline commit、允許修改的檔案、預期一個 hunk/一條 logical line,以及 private artifacts 的 SHA-256。

{
  "id": "boundary-01",
  "baseline": "3f61...",
  "allowed_source": ["src/is_adult.py"],
  "max_files": 1,
  "max_hunks": 1,
  "max_logical_lines": 1,
  "gold_patch_sha256": "9ab4...",
  "hidden_tests_sha256": "5c20..."
}

評分器本身也要有反例:固定回傳測試答案、刪掉函式、跳過測試、修改測試、碰 lockfile、整檔 formatter 與一個合法替代修法。前六種必須被殺掉,最後一種應標成 semantic pass / fidelity fail 並進人工覆核,而不是偷偷改成「錯誤」。這和Blast Radius Receipt互補:前者在高風險命令執行前縮小爆炸半徑,本文在修補完成後檢查實際 diff。

走一次完整判定:修對,但仍可能 fidelity fail

以第一題為例,契約寫「滿 18 歲即為成人」,故障版是 return age > 18,gold 只把 > 換成 >=。候選 A 做同一個一行修補,hidden boundary tests 與完整測試都通過,且沒有其他 diff,因此是 faithful solve。候選 B 也讓測試通過,卻另加一個 normalize_age() helper、型別轉換與例外處理;只要契約沒要求接受字串,它就是 semantic pass,但超出這題明定的一檔、一 hunk、一 logical line 預算。

候選 C 若寫成 return True,可能騙過只有 18 歲的 symptom test,卻會被 17/18/19 與負值的 hidden cases 殺掉,屬於 semantic fail。候選 D 若修改測試期待值,即使 CI 畫面全綠也要在 scope gate 直接阻擋。這個順序很重要:先問行為是否正確,再問是否越界,最後才討論 patch 大小;否則最短的錯誤答案反而可能拿到漂亮分數。

Receipt 可保留四個互不相抵的欄位:semantic_passscope_passlocality_passexcess_distance。不要把它們加權成單一分數,因為 100% 測試分數不該抵銷「Agent 改了 lockfile」這種破壞性事件;相反地,excess 較高也不該直接抹掉一個合理替代修法。

步驟三:同一配置跑一般 Prompt 與 preservation clause

兩個 arm 只能差一句話。一般版用「修正指定行為並執行測試」;preservation 版只加:「保留原有結構、命名與風格,只修改讓行為契約成立所需的最小範圍。」模型 snapshot、Agent 版本、系統規則、可用工具、turn/token budget、測試可見性與 sandbox 必須相同。

論文作者在 50 組 matched settings 報告:加入 preservation clause 後,通過修補的平均 excess distance 從 0.195 降到 0.131,added cognitive complexity 降 26.6%,Pass@1 增加約 2.3 個百分點;所有 50 組 excess distance 都往較小方向移動,但不是每個模型的每項指標都改善。這是該研究條件的結果,不是對目前 Claude Code 或 Codex CLI 的保證。

Codex 的官方非互動文件使用 codex exec,預設 read-only;要讓 isolated fixture 可寫,明確指定 workspace-write,並用 --json保存 JSONL events。Claude Code 的官方 headless 文件使用 claude -p,可設定工具、turn 上限與 JSON 輸出。若測的是 CLAUDE.md 行為,不要加會跳過 CLAUDE.md、hooks 與 skills 的 --bare

# 每次都從相同 baseline 建立新的 isolated worktree
codex --ask-for-approval never exec \
  --ephemeral --sandbox workspace-write --json - < task.md

claude -p "$(cat task.md)" \
  --tools "Read,Edit,Write" \
  --allowedTools "Read,Edit,Write" \
  --permission-mode acceptEdits \
  --no-session-persistence --max-turns 12 --output-format json

# Agent 結束後由外部 runner 留下不可變 receipt
git add -N .
git diff --binary HEAD > candidate.patch
git diff --numstat HEAD > candidate.numstat

這只是最小骨架:真正 CI 還要在 container/ephemeral runner 關閉網路,讓 Agent writable root 不包含 private tests 與 gold,並把金鑰限制在單一 invocation。Codex 官方也建議在權限分離的 job 保存 patch artifact,再由另一個 job 開 PR。可先用Coding Agent 最小設定減少本機全域設定污染。

步驟四:跑多次,但不要把 10 題做成模型排行榜

每個 arm 至少跑 3–5 個獨立 attempts,交錯執行順序,保存時間、模型識別、Agent/harness commit、Prompt hash、工具、權限、cost、latency、seed(若支援)與完整 patch。固定 seed 也不等於雲端 Agent 完全 deterministic。

  • Functional solve rate:visible+hidden+regression 全通過的比例。
  • Faithful solve rate:functional、scope、locality 三者同時通過。
  • Scope violations:tests、設定、依賴、lockfile、generated 或無關 source 被碰幾次。
  • Review surface:檔案數、hunk 數、additions+deletions;binary 另列。
  • Edit metrics:只在通過修補中報 excess token distance 與 added complexity 的中位數、分布;再列兩邊都通過的 paired intersection。

10 題中一題就是 10 個百分點,即使 10/10,樣本仍很小。它適合教學、每日 canary 與抓出破壞性越界,不適合宣布「A 模型勝過 B」。若要做 release gate,先擴充成分層 private set,再預先定義 non-inferiority margin 與 paired analysis。更完整的 Agent 評測觀念可延伸到AI Agent Harness 實作

報表怎麼讀?先看失敗型態,再看平均值

假設 preservation arm 的 faithful solve 從 6/10 變成 8/10,不要立刻寫成「提升 33%」。先展開逐題矩陣:新增的兩題是否只是同一種 boundary bug?原本通過的題是否出現 scope violation?若一般 arm 與 preservation arm 通過的題目集合不同,兩邊 passing-only 的平均 excess 也可能受到題目難度組成影響。最誠實的報法是同時列出 unconditional faithful solve、各自 passing repairs,以及兩邊都通過的 paired intersection。

也不要把三次或五次 attempt 當成三十或五十個獨立題目:同一 fixture 的重跑共享程式、測試與缺陷類型,彼此高度相關。小樣本最適合回答「這次版本有沒有突然開始改測試、整檔重排或新增依賴」;要回答「平均少改多少」則應保存完整分布、擴大題庫,並讓人工覆核不知道候選來自哪個 arm。

步驟五:接進 CI,硬規則與統計警報分開

Edit Fidelity CI 流程:隔離 Agent、保存 patch receipt、依序檢查 semantic、scope、locality,最後輸出非阻擋統計
單一候選 patch 的安全不變量可以 hard fail;10 題隨機模型 canary 先 report-only,避免一次波動誤擋 PR。

Candidate patch 的 deterministic gate 可直接擋:hidden/regression 失敗、修改 private artifacts、碰未授權路徑、加入依賴或 lockfile、超過一個 target file/hunk/logical line、增加控制流程。因為這 10 題的契約就是局部修補,門檻是 fixture policy,不是放諸四海皆準的研究定律。

set -euo pipefail
python eval_fixture.py --manifest private/manifest.json \
  --repo worktree --patch candidate.patch \
  --json-out receipt.json

# evaluator 依序檢查:baseline_fail、gold_pass、candidate_tests、
# protected_hashes、allowed_paths、files、hunks、logical_lines、complexity
jq -e '.semantic_pass and .scope_pass and .locality_pass' receipt.json

模型 canary 則先 report-only:顯示完整 10×attempt matrix,任何 destructive scope violation 立即 alert;一題的升降先重跑與人工 adjudicate,再決定是否歸因於模型更新。若失敗,把 rejected diff、測試 log 與 receipt 留在 artifact,回滾 isolated worktree,重新要求 Agent 縮小 patch,不能讓 Agent 自己宣布「我只改了必要部分」就過關。

研究 repo 可以直接重現嗎?目前要保留一條黃線

截至 2026 年 9 月 8 日,我們檢查的 701ad34 commit 可取得 400 題資料與主要程式,但不能據此完整重算論文表格:作者在 README 說明 raw generations、result files 與 checkpoints 尚未隨 repo 發布。更重要的是,README 的 explicit 範例同時使用 --generic --is_explicitCLI parser 卻明確拒絕這個組合;目前 evaluator 的差值方向也和論文公式相反,彙總路徑未明確只篩 passing repairs。

這不會自動推翻論文,但會阻止「clone 後一鍵重現」的說法。若你要驗證原始 400 題,先 pin commit、人工核對公式與 filter,再等待作者釋出 raw outputs 或更正;本文的 10 題流程刻意把 receipt 與 gate 寫成獨立實作,避免把已知落差帶入團隊 CI。

Edit Fidelity 常見問題 FAQ

1. 測試都通過,為什麼還要量 Edit Fidelity?

測試只覆蓋已寫出的行為;越界改檔、契約漂移與無關重構可能沒被抓到。Fidelity gate 是第二層 review surface 警報。

2. candidate 必須和 gold patch 完全相同嗎?

不用。Gold 是已知最小 witness,不是唯一正解;有效替代修法先過語意測試,再標示 fidelity 差異供人工覆核。

3. excess edit distance 大於零就一定是壞 patch?

不是。它代表比 gold 改得多,適合排序與警示;論文人工 audit 也找到有效替代修法,不能省略 adjudication。

4. 格式化變更要不要計入?

Raw diff 要完整保留;token 指標可另做格式正規化。整檔 formatter 在一行 fixture 仍應算 locality fail。

5. 3 個 seeds 夠嗎?

只夠 smoke test。至少 3–5 次可看出明顯不穩定;要判定小幅版本退步,需要更多 private tasks、重跑與配對統計。

6. 可以用這 10 題比較 Claude Code 與 Codex 誰較強嗎?

只能比較兩個被完整記錄的 deployment configurations 在這組局部修補題的表現,不能推論整體 coding 能力。

7. Gold patch 和 hidden tests 要放進 repo 嗎?

可放 private evaluator repo 或受保護 artifact,但不能進 Agent writable root。若題目公開,就應輪替參數與 private 變體。

8. 何時不該要求一行 patch?

功能開發、架構重構、跨檔 migration 或安全修補常需要更大範圍。這時改用任務專屬 scope manifest,不要硬套一行門檻。

給團隊的完成清單

  • 十題都具備 fail-before、pass-after、hidden contract 與 near-miss mutants。
  • Gold、hidden tests、manifest 與 hash 都在 Agent writable root 外。
  • 兩個 Prompt arm 只差 preservation clause,其餘配置完整鎖定。
  • 每次保存 binary patch、numstat、events、測試 log、cost 與 latency。
  • 先擋 semantic/scope/locality 硬失敗,再報 token distance 與 complexity。
  • 10 題 aggregate 先 report-only;人工處理有效替代解。

如果團隊已因 Agent 產生大量難以維護的間接層,也可讀Cognitive Debt;想把 fixture、receipt 與回歸策略整合成可重用工作流,前往 AlphaLab 的線上課程AI 專區

接著閱讀

左右滑動查看更多推薦

結語:讓 Agent 同時交出修補與保留證據

Edit Fidelity 最實用的價值,是把「感覺改太多」拆成可重跑證據。先用 10 題一行 Bug 建立窄而清楚的契約;再分開測 semantic、scope、locality 與 excess distance;最後保存每次 patch receipt。當 Agent 能說明修對了什麼,也能證明哪些地方沒有碰,測試綠燈才真正變成可安心 review、能追溯也能回滾,並讓審查者快速理解的修補。

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

每週最多三封:一封 Weekly 週報與最多兩封關鍵 Alpha Signal。

我們不會 spam,隨時可退訂。