文章

Claude Code 說做完了:是交付、審查,還是真的進了 main?

一顆綠燈底下其實躺著四件不同的事。Clawdline 把它們分開記,而且在 git 證明那顆 commit 真的在你指定的分支上之前,不會把任何一件工作標成已經合併。

有一句話你一定看過很多次:「已經修好了,測試全過。」

它通常是真的,卻沒回答你真正在問的:改動到底在不在你要出貨的那條分支上。「做完了」裡面壓著四件各自獨立的事,沒有一件會自動帶出下一件。

「測試全過」講的是四件事裡的其中一件

真正有用的是第三欄,只有它告訴你該去看哪裡:

「做完了」可能是哪一件 是誰在主張 什麼東西才算數
這個 session 認為自己做完了 session 本人,對自己的工作 沒有。這是主張,不是它自己的證據
有一個沒寫這段程式的人讀過,而且同意 一個跟這段程式沒有利害關係的讀者 一次講得出自己打開了什麼的審查:哪個檔案、哪一行,或哪道指令、輸出是什麼
那顆 commit 已經被你要出貨的分支涵蓋 repository 自己 git merge-base --is-ancestor $commit main
通過的那些測試涵蓋了這次改動 那一次測試執行 跑的是哪一組,以及對著哪一棵樹跑的

第三件和第四件最容易安靜消失。2026 年 8 月 26 日,我們自己的 repository 裡,整個檔案的 git add 兩次帶走三行程式,型別定義卻留在工作目錄。兩次提交的當下樹都是綠的,兩顆 commit 都單獨編不起來。

共用的工作目錄裡,那棵樹是所有人工作的總和,你的 commit 只有你那一份。在那裡跑綠的測試,回答的是那棵樹的問題,不是你正要推出去的東西。

session 自己說的
我做完了
離這份工作最近的那一方提出的主張。它是起點,不是證據。
另一個人/另一個 session
有人讀過,而且同意
一次講得出自己打開了什麼的審查:哪個檔案、哪一行。
git 說的
那顆 commit 真的在你要出貨的分支上
位元不會自己移動。中間還有整合,還有跟別條線撞在一起的可能。
那一次測試執行說的
跑綠的那些測試,跑的是含這次改動的那棵樹
在別棵樹上跑綠的,是一句關於別的東西的真話。
四件事,四個不同的主張者,而且沒有一件會自動帶出下一件。橘色那一點是唯一由 session 自己蓋的章——後面三個都不是它說了算。一個工具只給你一顆勾,等於替你把這四個主張者當成同一個。

只有一個 session、一個分頁的時候,直接相信它是對的

一個 agent、一個終端機、一個 repository:讀回報、瞄一眼 git log、往下做。相信它的代價,是它偶爾出錯那次你要往回捲一段;更講究的流程,你到星期四就不會再做了。

會弄壞這個安排的是算術,不是不信任。四個分頁,問一句「那個進 main 了嗎」要往回捲四次。一個星期後那個 session 早就關掉,它主張過的只剩一份沒人想再打開的對話記錄。

多花的那一點,換到的是四件事在各自成立的那一刻就被分開寫下來。

在 Clawdline 裡,這四件事是四個各自獨立的標記,而且沒有 session 蓋得了自己的章

每一列 session 帶著四個彼此獨立的狀態軸,而不是一顆好壞燈號,其中一個是「它還欠著什麼」。債要嘛被明確清掉,要嘛那個 process 整個換掉,不會自己消失。

一個勾是「已交付,等待驗收」,只能從綁在終端機此刻那個 process 上的任務結果或交付回報寫出來。審查、整合、合併都可能還沒發生。

第二個勾,App 不聽任何人一面之詞。要記下一次落地,你得說出目標分支和 commit。紀錄寫下去之前,App 會確認那顆 commit 是那條分支的祖先,不是就拒絕。那就是 git merge-base --is-ancestor:你自己的工具,由一個跟答案沒有利害關係的東西來跑。它不擋流程,待處理的落地不擋任何人;它唯一做不到的,是因為寫程式的 session 說了算就變成一個勾。

審查那一步也一樣:審查者回報成功不會讓它往前走。審查必須帶回一份針對三個具名面向的判定。改動有沒有做到規格說的事、有沒有踩到這個 repository 的規矩、出事時行為對不對。「我看過了,沒問題」是同意,不是查證。

這一切換來的畫面,是一份叫「做完了,沒有落地」的清單

那個接點是「專案」頁上那一組,名字就叫「做完了,沒有落地」。它自己的說明就是這篇的全部論點。沒有任何東西說它進了樹裡:沒有落地紀錄,也沒有一條 git 說已經合併的分支。事情做完了,只是沒有人整併。

每一列都帶著自己的「落地證據」,用 App 自己的說法。「root 驗證過並寫下紀錄」、「git:分支已經在 HEAD 裡」、「git:分支還沒有被合併」、「git:分支已經不在了」。旁邊寫著要怎麼把這一列清掉:讓它落地,或寫掉它。

那條證據線上還有第五種答案:「問不到 git」。觀測過期、缺漏或有歧義的時候,你拿到的是一句明講的「不知道」。不是一份把可疑的列悄悄拿掉的清單。有疑慮的證據不只少掉一列,它讓整份清單的完整性變成未知。一份你無法確定是否完整的清單,會被當成檢查表在讀。

Clawdfather 那一頁是從另一端看同一件事:由一個協調 session 保管整台機器的全局狀態,而不是每個 session 各留一份殘缺的副本。

它證明不了的事

那個涵蓋檢查問的是你機器上的一條分支,它證明那顆 commit 是你指名那條分支的祖先。不證明你推上去了、有人部署了,也不證明剛剛跑綠的測試跑的就是那棵樹。

記下一次落地,也不證明那次審查是獨立的。App 擋得掉一個 session 對自己狀態的主張,也查得了 commit 跟分支的關係。它沒辦法告訴你審查者有沒有真的打開那個檔案。

還有,一個在同一個工作目錄裡、完全沒有經過派工的人,對上面這一切都是隱形的。沒有任務、沒有那一列、沒有負責的人,也沒有一筆要還的落地。

就算不用我們的東西,那四欄你也留得住

把你本來記成一件的事記成四件,各自有位置。回報放回報該在的地方,審查放在它指名的檔案和那一行旁邊。合併那一件是一行指令:git merge-base --is-ancestor $commit main && echo on-main。測試結果在你把 git rev-parse HEAD 記在旁邊之前都不值錢,那正是「綠了」和「對著我要問的那棵樹綠了」的差別。

再來是沒有工具替你做的那一條規則。永遠不要讓做這份工作的那一方,去寫那個代表「它完成了」的標記。

工作流程指南依序講了派工、交付與落地。旁邊還有兩篇:怎麼把工作派出去、還來得及在第三分鐘喊停,以及兩個 session 共用同一個 git index 會發生什麼事。

常見問題

怎麼知道 AI agent 是不是真的把事情做完了?
先決定你問的是四件事裡的哪一件,因為它的回報只答得出第一件。這個 session 認為自己做完了嗎——那就是回報本身。有沒有一個沒寫這段程式的人讀過而且同意。那顆 commit 有沒有真的被你要出貨的那條分支涵蓋,這一件用一行指令就問得到:git merge-base --is-ancestor $commit main 回 0 或不回 0。以及剛剛跑綠的測試,跑的是不是含著這次改動的那棵樹。四件事,四種不同的缺席方式,而且沒有任何一件會自動帶出下一件。
Claude Code 可以審查自己剛寫的程式碼嗎?
它讀得動,但那不叫審查。同一個 session 讀自己剛產出的東西,缺的不是能力,是距離:那段文字正是它認為最合理的文字,而「確認」只要一句話,「查證」要打開一個檔案。比較有用的做法,是換一個沒有參與過的讀者,並且要求它把打開過的東西講出來——哪個檔案、哪一行,或哪一道指令、輸出是什麼。在 Clawdline 裡,一個審查步驟不會因為審查者回報成功就算過:它必須帶回一份針對三個具名面向的判定,而每一條發現都要有嚴重度,以及一個你自己去看得到的依據。
測試全過了,代表改動已經在 main 上了嗎?
不代表,而且在好幾個 agent session 共用同一個工作目錄的時候,這兩件事會常常分開。一次通過的測試,是關於它跑過的那棵樹的證據;而在共用的工作目錄裡,那棵樹是所有人工作的總和,你的 commit 卻只有你那一份。2026 年 8 月,我們自己的 repository 裡同一天就發生兩次:提交出去的那幾行,型別定義在另一個還留在工作目錄裡的檔案,兩次在提交的當下樹都是綠的。所以問題從來不是「綠了嗎」,而是「對什麼綠的」,以及你在問的那顆 commit 是不是你要出貨那條分支的祖先。