你跑過多少次安裝或設定指令?最後一行印出「✓ 已設定」「Done」,你就關掉終端機了。
你有沒有回頭打開它說改了的那個檔,看一眼?
我做的小工具 usage 有一個 usage setup 指令,跑完會印出這兩行:
✓ Codex status_line 已配置
ℹ 請重新開啟 Codex 一次
從 6 月 1 日到 8 月 28 日,有一種設定檔跑完這個指令,印的就是這兩行,檔案卻一個字都沒變。
usage setup 要改的是哪個檔usage 是我做的開源小工具,顯示 Claude Code、Codex 等 AI 工具的用量。usage setup 會把用量資訊掛到 Codex 畫面底下那一行狀態列,像是目前的專案、git 分支、Codex 每 5 小時的用量上限還剩多少。
做法是改 Codex 的設定檔 ~/.codex/config.toml。這個檔是 TOML 格式(一種用 [名稱] 分區塊的設定檔寫法),usage 要在 [tui] 這個區塊底下加一行 status_line = [...]。
程式分四步:
tui 這個區塊。[tui] 這一行,把 status_line 插在它下面。tui,原文裡卻找不到 [tui]第 1 步和第 2 步,看的是兩種東西。
第 1 步用 TOML 解析器(讀懂設定檔格式的程式)問「有沒有 tui」。第 2 步在原文裡找 [tui] 這幾個字。
Codex 的設定檔可以長這樣:
[tui.model_availability_nux]
"gpt-5.6-sol" = 4
[tui.model_availability_nux] 是 tui 底下的一個小區塊。解析器看到它,就說有 tui。可是整個檔案裡,沒有單獨一行 [tui]。
第 2 步找不到那一行,把原文原封不動交回去。第 3 步把沒變的內容寫回檔案。第 4 步照樣印 ✓。

這種寫法是從哪來的?後來修正這個錯的 PR #116(送上來請求合併的一組改動)說明裡寫,[tui.model_availability_nux] 是 Codex 自己加進設定檔的。
我把 usage 四個時間點的程式各拿出來:6 月 1 日一次改動的前後、8 月 28 日修正的前後。每一版都餵同一份只有 [tui.model_availability_nux] 的設定檔,跑一次設定。檔案放在暫存資料夾,不碰我自己真正的 Codex 設定。

只看印出來的那行,分不出哪兩個真的寫進去了。
6 月 1 日之前,第 1 步是直接在原文裡找 [tui] 這幾個字,找不到就在檔尾補一個 [tui] 區塊,這份設定檔寫得進去。
6 月 1 日那次改動,是 v0.13.0 發版後把程式檢查一遍、一次修掉 7 個 bug 的 commit(存進版本紀錄的一次改動)。其中一條要修的是:原本插入時會把原文裡每一個 [tui] 字樣都換掉,連註解裡的也算。
修這條的時候,第 1 步改成問解析器,第 2 步還是在原文裡找單獨一行 [tui]。碰到只有小區塊的設定檔,兩步就對不上了。
從下一版 v0.14.0 到 8 月 27 日的 v0.30.1,usage 一共發了 137 個版本號,每一版的 usage setup 碰到這種設定檔,都會印 ✓、不寫入。
修正之前,直接跑這段設定的測試有 5 個。其中 4 個不是只看有沒有印 ✓,而是跑完把設定檔讀回來,檢查 status_line 有沒有在裡面。第 5 個測的是設定檔讀不到時,會不會印警告。
檢查的方向是對的。問題在餵進去的設定檔:那 4 份不是有單獨一行 [tui],就是完全沒有 tui。[tui.xxx] 這種小區塊的寫法,在整個測試資料夾裡一次都沒出現。
測試裡的設定檔,是寫程式的時候想像出來的。真的設定檔用久了,會出現測試沒想到的寫法;這次這種,照 PR 的說法,是 Codex 自己加的。兩邊不一樣,測試就照樣全綠。
測試沒抓到,程式自己其實抓得到。6 月 1 日同一次改動,還加了一個函式 is_codex_setup():讀設定檔,看 usage 的 status_line 在不在裡面。
前面四個版本那次實跑,跑完設定之後我也直接呼叫了它。沒寫進去的那兩版(6 月 1 日改動後、8 月 28 日修正前),它都回答「不在」。usage codex(顯示 Codex 用量的指令)這條我沒實際跑,照程式碼,這時候會提示:
狀態列尚未設定。請執行:usage setup
照著再跑一次 usage setup,還是印 ✓。
程式有能力知道設定沒寫進去,只是印 ✓ 之前,沒有回頭問一次。
8 月 28 日凌晨,合併進來的 PR #116 修掉了這個錯。它做了兩件事:
[tui.xxx] 前面補上 [tui]。⚠ ~/.codex/config.toml 的格式無法自動修改,請手動調整 status_line
設定檔裡本來就是 usage 的 status_line 的話,不會走到這一步:程式讀完檔就先停下,印「已是 usage 設定,略過」。
測試也補上了小區塊的設定檔。
同一晚審這個 PR 時,又找到一處一樣的毛病,在反安裝(把 usage 加的狀態列拿掉)那邊。設定檔如果不開 [tui] 區塊,而是直接在最上面寫 tui.animations = false,修正後的 usage 會跟著寫成 tui.status_line = [...],檔案裡還是沒有單獨一行 [tui]。反安裝的程式仍在找那一行,找不到就原樣寫回,照樣印「已移除」。這處在合併前就補上了,沒有發出去。
測試資料補得再齊,也追不上真實設定檔之後會出現的新寫法。不管設定檔長成什麼樣子,都擋得下「沒寫進去」的,是第 4 步:印 ✓ 之前先確認。
印 ✓ 的那一行,只代表程式走到了最後一步,不代表它說的事真的發生了。要知道有沒有發生,得去看它說改了的東西:打開那個檔,或者用另一個方法問一次,像 is_codex_setup() 那樣。
AI 的回報也是一樣。你叫它改 .env、改 CI 設定,它回「已更新」「已寫入」,那是它對自己的描述。驗收的時候,要看的是它說改了的那個檔。
現在就可以做一件事:找一個你最近跑過的安裝或設定指令,或是 AI 回報說它改好了的一個設定。
比一次它說改了的那個檔。檔案在 git 專案裡,用 git diff;不在的話,下次跑之前先複製一份,跑完用 diff 比兩份。
有差異,這一次是真的改了。沒差異卻印了 ✓,你剛剛找到一個會說謊的 ✓。
工作單(交給 AI 的任務說明)裡有一格「做完怎麼算對」,Day 4、Day 8 到 Day 13 各在這格加了幾行。今天再加一行:
做完怎麼算對:
- (Day 4、Day 8 到 Day 13 加的幾行)
- 會改檔或改設定的功能:成功訊息不算數,AI 回報要附改動前後的比對;測試要拿一份真實環境裡用過的檔案跑一次,不能只用自己想像的寫法
今天的 ✓,是程式對自己的描述。明天換一種問題:程式沒有壞,只是越改越大。usage 寫給 AI 看的說明檔裡有一條規則:新功能不准再往 menubar.py(選單列介面的程式檔)裡塞。這個檔被拆過兩次,兩次都長回去,7 月 29 日長到 2485 行;說明檔自己寫著,這條規則「目前被無視」。7 月 31 日,它從說明檔搬進了 CI。