我們花了很長一段時間在一件聽起來很無聊的事情上:確認我們的檢查,真的有在檢查。這篇記錄的是那個過程——為什麼一個門會說謊、我們整理出的十二種「說謊的形狀」、以及我們怎麼從「一個一個撞到」變成「一次掃完」。裡面有不少是我們自己踩的雷。

先講一個具體的。
我們流程的第 25 步有一個電遷移(EM)的門,第 33 步有一個功耗預算的門。兩個都是 blocking——不通過,流程就不該往下走。
我們拿一個完全空的目錄去跑它們。兩個都回傳 0,也就是通過。
而它們自己印出來的最後一行是這樣寫的:
INCOMPLETE: electromigration was NOT screened — missing authority: per-layer Jmax
INCOMPLETE: total power was NOT compared against anything — missing authority: L19...
它們知道自己什麼都沒檢查,也說了自己什麼都沒檢查。但流程讀的是離開碼,不是那段話。所以一個空目錄通過了兩個 blocking 門。
這不是有人偷懶。寫這兩個門的人把「我沒有足夠資訊」誠實地印出來了,只是把它歸類成「不算失敗」,於是走了回傳 0 的那條路。誠實寫在文字裡,沒有寫在出口。
我們把這種東西叫做「說謊的檢查」。它不是壞人,它是一個沒有能力說出真話的機制。
人在跑流程的時候,會順手看一眼輸出。看到「NOT screened」,人會停下來。
AI agent 不會。它讀離開碼,然後往下一步走。
更麻煩的是:我們建這整套東西的目的,就是讓機器可以在沒有人盯著的情況下跑完一顆晶片。而「沒有人盯著」的前提,是那些門講的是真話。一個會說謊的門,在有人看的時候只是個小瑕疵;在沒有人看的時候,它是整條鏈上唯一一個把假的當真的地方,而且它上游下游的每一份報告都會忠實地把那個「通過」抄下去。
所以我們才會在這件事上花這麼多力氣。它不是品管,它是這條路能不能走的前提。
2026-08-20 更新:流程後來長到 68 步 —— 2026 年 8 月新增了五個條件式的流片步驟(0.5ic、15.5ic、26.5ic、37.5ic、37.5ip)。下面的普查數字維持當初量到的原樣,對象是當時存在的 63 個步驟。用 68 步重跑會得到另一組數字,本文沒有宣稱那組數字。
當時我們的流程有 63 個步驟。2026 年 7 月我們做了一次盤點,決定不再問「這個步驟有沒有測試」,而是對每一個步驟問同樣的八個問題,後來加到九個。63 × 9 = 567 格,每一格都要有一個答案。
D9 是最後加的,也是最難的。前八個問的是「這個門有沒有好好接起來、會不會動」;D9 問的是「它有沒有真的看進去」。一個門可以在 D1 到 D8 全綠,然後在 D9 上發現:它只是確認了那個檔案在,從來沒有讀過裡面寫什麼。
這裡有一個我們自己走過的彎路,值得說。我一開始把 D9 設計成「拿正確答案來比對」——也就是要有一份 oracle。老闆一句話把它退回來:
我們自己訓練跟收斂的時候,當然可以用 oracle。但真正在跑的時候,哪來的 oracle?
他是對的。真實的專案不會附一份標準答案。所以 D9 被重寫成不需要 oracle 的五種判準:報告能不能自洽、能不能跟另一份產物交叉比對、能不能對回規格、能不能被物理定律夾住(例如:一條線上的電流不可能大於供給它的總電流)、以及最後才輪到專家判斷。重寫之後,可以審的格子從 22 格變成 63 格。
撞久了會發現,這些門說謊的方式是有限的幾種,而且每一種都留下機械化的痕跡。我們把撞到的整理成十二種:
第 12 種是最難抓、也最常見的一種。它每一步都對,只是問錯了問題。
問題是:上面這十二種,我們都是撞到的。修完一個,過幾天又冒出一個。
後來老闆問了一句很直接的話:「難道我們不能地毯式地把每一個 gate 都先判斷一下有沒有這種問題嗎?」
可以。而且我們手上其實已經有一大半零件了——只是十二個偵測器各自為政,從來沒有人對「同一個門在十二個維度上分別如何」給過答案。所以每次只能靠撞。
於是我們寫了一支普查工具,把流程裡宣告的每一個門條款抓出來,對每一個跑一輪探針,每個門發一張成績單。
這裡有一件事比工具本身更重要,我想特別寫出來:我們先驗證這支普查工具自己會不會說謊。
一個從來沒有觸發過的偵測器,跟沒有偵測器是一樣的。所以我們拿前面那兩個已經修好的 EM 和功耗門去校準,兩個方向都跑:修好的版本必須報 CLEAN(結果是 CLEAN),把修好之前的版本放回去必須被抓到(結果抓到了,而且一字不差地重現了當初的證據)。兩個方向都驗過,我們才敢用它的數字。
136 個門條款,四個秒級探針:
LIAR 18 (其中 15 個是 blocking)
SUSPECT 32
但這個數字要打折,而且必須由我們自己來打。
那 18 個裡面,有 5 個是先前已經審過、而且判定「空目錄就該通過」是對的——例如一個檢查「不該存在的產物有沒有出現」的門,空目錄本來就是它的正確答案。我們的探針對這類 fail-safe 的門會誤報。
扣掉之後,真正沒有人判過的是 13 個,其中 10 個是 blocking。也就是說:流程裡有十個「不通過就不該往下走」的門,會對一棵空樹放行,而且從來沒有人決定過那樣是對的。
另外 32 個 SUSPECT 全部來自同一種形狀——它們的輸入選擇器有無界的目錄walk,而且檔案裡找不到任何「只收 git 追蹤的產物」之類的護欄。那不代表它們錯了,代表它們有能力拿到假資料而沒有東西攔著。我們已經被這個咬過一次。
還有七種形狀還沒進普查(要跑 mutation,比較貴)。所以這個數字只會往上,不會往下。
挑幾個真的改變了我們做法的:
一個測試,是靠另一個測試偷偷幫它把樹修好才通過的。有個測試斷言「每個 skill 檔都要有某一段」。它是綠的。但那個檔案出貨時根本沒有那一段——是同一個檔案裡排在它前面的另一個測試,在跑的過程中把檔案改好了。我們把那個「會修好」的測試單獨拿掉再跑,它立刻變紅。所以那個「15 passed」其實是 14 個誠實的通過,加一個搭便車的。
跑測試會改寫已發布的證據。我們讓完整套件在一棵乾淨的樹上跑,跑到一半去看,發現它覆蓋了三個已發布 cell 的閘門報告——把「這份結果是從哪裡來的」改寫成最後一次跑測試的那個暫存目錄。那個路徑明天就不存在了。
一個「取得真實資料」的函式,回傳了測試自己的 fixture。它先找三個具名的路徑,找不到就退回去掃整棵樹。那三個路徑因為別的原因被下架之後,它掃到的第一個檔案是測試自己造的假資料,然後兩個名字裡有 real 的測試把它當成真實萃取結果在斷言。它被抓到純粹是運氣——那個 fixture 剛好跟斷言矛盾。換一個不矛盾的 fixture,它會一路綠燈。
還有一個是我自己的。我寫了一支普查程式去驗證別的東西,跑完回傳空的。56 個 agent 做完的工作,被我自己彙整程式碼裡的一個型別錯誤丟掉了。我從紀錄檔把它救回來,也把彙整修好了——但那一刻的教訓很清楚:會說謊的不只是被檢查的東西,還包括檢查用的工具,包括我自己寫的。
這支普查工具不會告訴你一個門的規則對不對。判斷「這條 DRC 規則是不是這個製程該有的」需要專家,那是另一件事。
它只回答一個比較窄、但可以機械化的問題:這個門有沒有能力說謊?——它會不會對空的東西放行、它能不能變紅、它說的跟它回傳的一不一致。
一個通過這個普查的門,仍然可能是錯的。一個沒通過的門,就算規則是對的,也不能信。
我們也還沒掃完。七種形狀還沒進去,那 32 個 SUSPECT 還沒有一個一個判過,10 個 blocking 的還躺在那裡等修。我們把數字寫在這裡,不是因為它好看。
如果這篇有什麼可以帶走的,大概是這句:當你開始讓機器在沒有人看的地方替你做決定,你要問的第一個問題不是「它做得對不對」,而是「如果它做錯了,有什麼東西會告訴我」。而那個「會告訴我的東西」,本身也需要被驗證——用它自己會被觸發的方式。
延伸閱讀:這 68 個步驟的全貌在流程頁;每一格門的狀態在閘門矩陣;程式碼全部在 GitHub 上,包含這篇提到的每一個 issue。