「我憑什麼相信這份 log 沒被改過?」

這句一出來,前面準備的材料大概都用不上了。時間戳有、工具名稱有、參數也有,問題從來不在資料缺不缺。那份 log 是你的服務寫的,存在你的資料庫,由你的人維運。旁邊能墊的是 SOC 報告、政策文件、廠商自述,三份都在講「我們有流程」,沒有一份講得了那一刻發生了什麼。

agent 讓這件事更難。它自己決定叫哪個工具、叫幾次,事後要重建的是一串它自己排出來的動作,每次長度和內容都不一樣。

缺口是真的。有一份規格正在對著它寫,叫 TRACE,八月底進了 Linux Foundation。剩下的問題只有一個:你現在該不該動手。

先講一件發生在它自己身上的事。CHANGELOG 有一則在修的是文件錯誤:TraceSandboxAdapter 的 docstring 原本寫著 It will not let a caller claim hardware it does not have。實際上那個 sandbox 只驗形狀:platform 字串在列舉裡、measurement 長得像 sha256: 開頭就算過,quote、簽章、nonce 一個都沒檢查。捏一個 amd-sev-snp 配一串零當 measurement,build_trust_record() 照收、schema 照過、簽章照簽。專案自己的結論寫得很坦白:

the check that was missing had never existed and was never implemented, only claimed.

它問的三個問題,比它的十五個欄位好懂

規格把要證明的事收斂成三句話,每句都刻意放了 actually 這個字。What actually ran、What did it actually do、What rules were actually in force。

第一句要的答案不在部署清單上,也不在 manifest 裡:客戶資料被處理的那一刻,記憶體裡正在執行的是什麼。第二句問叫了哪些工具、帶什麼參數、碰的資料是哪個分級。第三句問當下綁的是哪一份政策,以及它跑在什麼 enforcement mode。

三句話對應一份叫 Trust Record 的東西,十五個欄位,除了標 OPTIONAL 的以外全部必填。runtime 裝 TEE 從韌體一路到 workload 的量測鏈,tool_transcript 裝 MCP 與 A2A 的呼叫逐字稿,policy 裝政策雜湊加執行模式,cnf 把記錄綁到 TEE 裡那把簽章金鑰上。

它自己講得很白,這東西不是另一套平行堆疊:

TRACE is a profile, not a parallel stack. It binds existing primitives into one coherent artifact.

底下全是既有零件:RATS/EAT 當信封,SLSA 管建置來源,SPIFFE/SPIRE 給 workload 身分,SCITT 當 append-only 日誌,EAR 裝驗證者的判定。AIBOM 以 digest 被 model 引用,C2PA 被標成 adjacent, not absorbed。

願意寫下「我沒有發明新東西」的規格,通常是設計者知道採用成本才是真正的門檻。

被偷走的金鑰會替自己作證

規格裡最值得讀的一段,跟 agent 沒什麼關係。

假設有人拿到你簽 Trust Record 的那把金鑰。撤銷之後,第一時間會想到的規則一定是:拒絕所有 iat 晚於盜用時間的記錄。乾淨、直覺、寫進驗證器大概三行。

它不成立。規格拿一整個小節否掉它,小節標題就叫 Why iat cannot carry the boundary:

A compromised record-signing key also signs the iat field, so an attacker holding the key backdates it and the rule passes.

iat 本身就是被簽的欄位。握有金鑰的人可以把時間往前寫,寫完再簽,驗證器看到的是一份簽章合法、時間落在盜用前的記錄。把撤銷的邊界錨在一個「被攻破的金鑰自己控制得到的欄位」上,它就會被它要擋的那件事打敗。這跟時鐘偏差無關,容忍值怎麼調都沒用。

解法是換錨點,改用透明日誌的 entry ID。條目單調遞增,而且用密碼學綁在 Merkle 結構上,日誌往前走過之後,攻擊者沒辦法替事後補交的記錄挑一個更早的編號。所以撤銷宣告不寫「幾點之後失效」,寫的是 last_valid_entry_id:被撤銷金鑰簽的記錄,只有在它的 inclusion entry ID 小於等於這個值時才有效,大於就 MUST 拒絕。不同日誌的 entry ID 不可互比,這條也是 MUST NOT。

還有一條連帶設計:撤銷宣告不能自己簽自己,替金鑰 K 發宣告的那把金鑰階層必須高於 K。不然拿到 K 的人可以自己發一張撤銷宣告,把 last_valid_entry_id 填在他偽造的那批記錄後面,撤銷機制當場變成攻擊工具。

這段值不值得你把 TRACE 裝起來?不值得。但它值得你回頭看手上任何一套「出事就撤銷」的機制,問同一個問題:我判斷有效範圍用的那個欄位,是不是被撤銷的那把金鑰自己填的。

欄位有值,跟有人檢查過,是兩件事

enforcement_mode 除了 enforce 跟 silent,還有第三個值叫 declared。它的意思是:這份政策被指名了,也被綁進簽章記錄了,然後沒有任何東西評估過它。

The three modes above all assert that something evaluated the policy. declared asserts less: the policy is named and bound into the signed record, and nothing evaluated it.

規格說這不是邊角案例,沒有政策引擎的產生者很常見。接著把它釘死:declared 是最弱的值,MUST NOT 當預設;真的評估過政策的產生者 MUST NOT 用它;消費者 MUST NOT 把它讀成任何規則被檢查過的證據。

在格式裡留一個位置給「我什麼都沒做」,比多加十個欄位有用。

開頭那份 docstring 就是反過來的例子:沒有任何東西檢查過,文件卻寫得像有。

同一批 CHANGELOG 還有一則同族的:另一個 adapter 對每一份產出的記錄都蓋上 appraisal.status = "affirming",而那是驗證者才有權填的欄位。想從那一格確認有沒有人檢查過的人,得到的是一份沒人評估過的記錄給的肯定答覆。

第一條判準就在這裡。記錄上 runtime.platform 寫著 amd-sev-snp,不代表有人驗過硬體證明。專案文件講得很白:改 platform、複製一串非零的 digest、把 appraisal.status 設成 affirming,都不會讓證據憑空長出來。

它真的還很早,而且名單要自己數

2026-09-18 查的時候,trace-spec 這個 repo 有 30 顆星。參考函式庫 agentrust-trace 從 2026-06-05 首發到 2026-09-06 共 12 個版本,最新 0.10.0。repo 在 2026-09-17 還有 push,CHANGELOG 的未發布區塊長得像工程報告,每則都帶 issue 編號。活躍度是真的,規模不是。

規格首頁掛著警語,這是 pre-ratification draft,欄位、線路格式、符規要求在 v1.0 前都可能改。它也已經改過一次狠的。

v0.1 的 EAT profile URI 是 tag:agentrust.io,2026:trace-v0.1,而 agentrust.io 從來不是這個專案控制的網域,指向的是第三方停放頁。RFC 4151 只允許在鑄造者確實控制該網域時使用 tag URI,所以那個識別碼不是拼錯,是無效:它對一個屬於別人的名字宣告了權威,對方隨時可以在那裡立一份衝突的定義。

v0.2 的處理叫 Cutover, not coexistence,驗證器 MUST 拒絕舊識別碼、MUST NOT 兩個都收。

治理這塊要看仔細。Linux Foundation 在 2026 年 8 月 25 日宣布接手,新聞稿寫的共同開發者是 AMD、Intel、Microsoft、OPAQUE、TII。

而規格 §6.2 那份漂亮很多的名單,標題是 Target contributing organizations,內文寫著這些組織「被認定為天然的貢獻者」,「正式參與取決於各組織自己的獨立決定」。§4.4 的共同編輯席次寫的也是 Co-editor slots open for。

那是招募公告。

查的過程裡看到有二手報導把兩份名單混在一起,把目標名單上的公司寫成共同開發者。這件事本身就是判準:新聞稿列的參與者,跟規格自己列的目標名單,要分開數。

什麼時候簽了反而比不簽麻煩

最該想清楚的是沒有人會去驗。驗證有八個步驟,只有前兩步對著記錄本身做,剩下六步全要驗證者自己先備齊材料:廠商公布的 RIM、預期的政策 bundle、指名的透明日誌、信任的 builder,還有一份沒過期的撤銷 bundle。最後那項最容易誤會,規格說驗證不回呼發證者,聽起來像斷網也能驗,但簽章有效性是永久的、信任不是,被撤銷金鑰簽過的記錄離線驗永遠都會過。所以規格明訂過期的 bundle 不算通過。你產得出記錄,不代表對面驗得動。

最常見的一種:你的 agent 根本沒跑在 TEE 裡。那你產得出的是 Level 0 的軟體簽章,延遲不到 1 毫秒,能證明的事情也就到「這份 JSON 是我簽的」為止。防竄改日誌用現成的東西就做得到,不必扛一份 pre-ratification 規格。

產生環境 宣稱的簽章延遲
軟體(Level 0) < 1 ms
TPM 50 到 200 ms
SEV-SNP 10 到 50 ms
TDX 10 到 50 ms

驗證端所有情況都在 5 ms 以內。這些是 LIMITATIONS.md 的宣稱值,文件沒交代是在什麼機器、什麼負載下量的。

工具不跨協定邊界的話,那一格會很乾淨,乾淨到沒有意義。tool_transcript 抓的是穿過 MCP、A2A 這類邊界的呼叫,編譯進二進位檔裡的函式規格明寫不在範圍內。而真的跨了邊界的人,現在也還在等:參考實作叫 Confidential MCP,很容易讓人以為已經可以用,但 v0.2 明寫規範性的 MCP profile 不在這一版,目標是 v0.3。A2A 也一樣,delegation 區塊落在 v0.2,規範性的綁定規則排在 v0.3。

還有一件很容易被期待錯的事:它不管模型行為。prompt injection、越獄、幻覺、對齊漂移,五條永久範圍邊界裡明列不處理。

TRACE does not prevent misbehavior. It makes misbehavior crossing a protocol boundary visible at the moment of execution.

它證明什麼東西執行過、當時哪些對策在生效,不裁決模型的輸出對不對。

這篇的邊界

這篇讀的是 TRACE v0.2 規格原文、LIMITATIONS.md、trust-levels.md 與 CHANGELOG,加上 GitHub 與 PyPI 的 API 回應。我沒有跑過 agentrust-trace 任何一行程式,沒有產生過也沒有驗證過任何一份 Trust Record。文中的欄位名、MUST 條文、延遲數字都是規格與文件裡的文字。

所以現在要做什麼

回到開頭那句話。

現在不要導入 TRACE。但現在就去跑它那份驗證清單。把那八個步驟當成八個問題丟給自己的系統:那一刻在跑的是哪一版模型,你證明得了嗎。工具呼叫的記錄有沒有跟執行環境綁在一起,還是各存各的。你的政策是被評估過,還是其實就是 declared。金鑰被偷的那天,你用來判斷哪些東西還算數的依據,是不是那把金鑰自己簽的欄位。

這四題跟 TRACE 會不會成功沒關係,但答不出來的每一題,都是稽核那天你會卡住的地方。

什麼會讓我改口說可以裝了?兩件事:v0.3 出來、規範性的 MCP profile 真的落地;以及出現一個不是由規格作者自己營運的透明日誌,那題還掛在規格的開放問題清單上。稽核方會不會接受這份格式,我猜跟日誌那題一起決定,不過規格沒這樣寫,這條算我自己加的。

那四個問題今天就問得出口,不需要等誰先批准一份規格。TRACE 撐不撐得到 v1.0,等它撐到再說。