你用 AI 做了一個小工具。在自己電腦上跑得好好的,測試全過,你把它打包發出去。
別人裝起來,一打開就壞。你在自己電腦上從來沒遇過。
前七篇講怎麼下指令。從今天起換一個問題:每次改完,怎麼確認沒改壞。Day 4 講過,AI 說它檢查完了,你還是要自己打開、親手按一次,因為有些問題只有按了才看得到。今天要補一句:你按的那一份,跟使用者拿到的那一份,可能不是同一個東西。
usage 是我做的開源小工具,放在 Mac 螢幕最上面那排選單列,顯示 Claude Code、Codex 這幾家 AI 工具的額度和花費。除了選單列,它還有另一種開法:在終端機(打指令的那個黑色視窗)裡開一個純文字的儀表板,叫 TUI。
9 月 4 日深夜,一個我不認識的使用者在 GitHub 開了 issue(專案的問題回報區)。他用 Homebrew 裝好 usage 的 App,在終端機打一行指令,叫 App 裡的程式開 TUI。結果畫面還沒出來,就跳出一個啟動失敗的錯誤視窗。他附上錯誤訊息,還自己拆開 App 查到原因:App 裡少了幾個檔案。連怎麼修都寫好了。
隔天早上我看到,把 issue 截圖丟給 Claude,只問了一句:
什麼問題
Claude 回的第一句是:「他報的是真的,本機也對得上。」它對照我電腦上裝的那份 App,裡面一樣少了那幾個檔案。
TUI 的表格是用一個叫 rich 的套件畫的。畫之前,rich 要先知道每個字佔幾格寬:英文字母佔一格,中文字佔兩格。這些寬度記在 21 個檔案裡,rich 平常不先載入,畫到那個字才去拿。
usage 用一個叫 py2app 的工具,把程式打包成 Mac App。它會先掃一遍程式碼,看到哪些檔案被用到,就把哪些裝進 App。「畫到才去拿」的那 21 個檔案,掃的時候看不到,就沒裝進去。App 裡的 TUI 一開始畫表格,找不到檔案,當場崩潰。
修法是改打包設定:rich 不讓打包工具自己掃,整個資料夾照搬進 App。我回 Claude:
你處理就好 處理好 回覆 發新版回去?
十幾分鐘後,新版發出去,Claude 也回覆了那位使用者、把 issue 關掉。
Claude 寫的更新紀錄是:從 App 啟動的 TUI「又能開了」。聽起來像是以前能開,最近哪次改動才弄壞。
寫這篇的時候,我想知道它壞了多久。Claude 先懷疑 7 月 9 日那次:rich 升了一個大版本。它把升級前的最後一版,7 月 7 日的 App,下載回來開 TUI:一樣崩。再往前找到 5 月 18 日,usage 第一個能下載 App 的版本:也一樣崩,錯誤訊息一字不差。9 月 5 日修好的那版,才畫出完整的畫面。
再翻打包設定的修改紀錄:管 rich 的那幾行,5 月 17 日寫下,到 9 月 5 日修好之前沒動過。從 5 月 18 日到 9 月 1 日,usage 發了 189 個版本,每一版都有 App 可以下載。打包好的 App 裡,TUI 從來沒打開過。

這段期間不是沒有檢查。usage 從第一天就接上 CI:每次把程式推上 GitHub,自動跑一輪檢查格式、型別、測試,全過就亮綠燈。到 9 月初,測試已經有一千九百多個。發版時,GitHub 上的出貨流程也會先把測試跑一遍,全過才開始打包。
測試裡也有測 TUI 的,都過了。可是測試跑的是原始碼:開發環境裡 rich 整個裝好,21 個檔案都在,怎麼畫都不會缺。
原始碼測完,打包成 App,接著只做一件檢查:確認 App 裡有四個檔案,狀態列用的腳本、兩張圖示、一份設定檔。四個都在,就壓縮上傳。9 月 5 日補新檢查的時候,Claude 在說明裡寫得很白:
打包後的驗證原本只確認四個檔案存在就直接壓成 zip 出貨,沒有任何一關會執行那個 app。
9 月 1 日發版那天,Claude 回報:CI 綠、打包上傳完成,我電腦上也裝好新版、跑起來了。這些都是真的。跑起來的是選單列。README(專案首頁的說明)也從來沒教過從 App 開 TUI,寫過的開法都是從原始碼開。App 裡的 TUI 那條路,第一個走過來回報的,是 9 月 4 日那位使用者。

修好 TUI 的同一天,Claude 在出貨流程多加一關:打包完、上傳前,在 GitHub 的 Mac 機器上真的把 App 裡的 TUI 開起來。用假資料開,不讀真實的用量紀錄;最多等 60 秒,等到畫面最外圈的框畫出來才算過,中途出現錯誤訊息就擋下,不出貨。那個框要整個畫面都算好、畫完才會出現,所以看到它,就代表這一輪沒崩。
加好之後,Claude 先複製一份 App,故意刪掉那 21 個檔案,拿這一關去跑:擋下來了,錯誤跟 issue 裡一模一樣。拿正常的 App 跑,順利通過。
當天下午發的下一版,是第一個先打開過才出貨的版本。
換到你的專案,問題是同一個:你測的那一份,跟使用者拿到的那一份,中間隔了什麼?
中間那一步只要漏了東西,原始碼那邊的測試看不到。
usage 其實做過一次對的。8 月加了一種新的裝法:uvx usage-cli,一行指令從 Python 的套件庫下載、直接執行,不用裝 App。加的時候,CI 同時多了一關:把打包好的套件裝到專案資料夾以外的地方,執行一次,確認它印得出版本號、吐得出格式正確的用量資料。只是 App 裡的 TUI 這個 5 月就有的入口,要等到 9 月那位使用者開口,才補上同樣的一關。
先列出你的東西有幾種開法。每一種寫兩件事:使用者從哪裡拿到它,出貨前有沒有任何一步真的把它打開過。
然後在工作單(交給 AI 的任務說明)「做完怎麼算對」這一格,在 Day 4 的兩行後面,多加兩行:
做完怎麼算對:
- 你自己驗:___(把跑了什麼、結果是什麼貼在回報裡)
- 我自己按:打開___,按___,應該看到___
- 出貨前開一次:拿使用者會拿到的那一份(安裝檔/部署後的網址/裝好的指令),照使用者的開法打開___,應該看到___;出現錯誤就不准出貨
- 寫進出貨流程:上面這一步每次自動跑,不靠人記得
發版前,叫 AI 指出來:出貨流程裡,是哪一步、哪一行,把使用者會拿到的東西真的打開過?指不出來,就當作沒有。
今天那一關,Claude 加完先故意弄壞一份 App,確認它擋得住。明天看一個沒這樣確認的例子:一個別人送來的測試,換回還沒修的舊程式,照樣全綠。
2c6bb7b):https://github.com/aqua5230/usage/commit/2c6bb7b9666e57):https://github.com/aqua5230/usage/commit/9666e57