上一篇將 harness engineering 的信任鏈拆成四個環節:Contract(合約)、Evidence(證據)、Attestation(獨立確認)、Authority(授權)。本文接著談第一環:如何把「要做什麼」說清楚、固定下來,讓後面的驗收真的有東西可以對照。
前言
使用 coding agent 時,最容易被低估的問題,往往是它會不會在過程中重新解讀需求,而不只是它會不會寫 code。
需求已經約定好,範圍也說得清清楚楚。agent 開始動工,過程中一路調整、一路「幫忙想得更周到」。等到交出成果,diff 裡的每一段單獨看都很合理 —— 但整體加起來,卻不太是原本要的東西。
範圍悄悄長大了一點、某個原本說好「不做」的地方被順手做了,甚至有些約定在過程中被重新解讀。最後很難指出到底是哪一個時間點出了問題,只知道成果和一開始談的內容已經有一段距離。
這類問題很容易被歸咎於「模型不聽話」。但回頭看流程,問題往往更基本:當初講好的內容,從頭到尾就沒有被固定下來。
需求散落在 issue、聊天記錄、口頭討論裡,而這些內容都可以被重新詮釋。既然「完成的定義」可以事後被改寫,後面的驗收就很難有明確依據 —— 最後甚至可能在不知不覺中接受「這樣好像也算做完了」的結果。
所以信任鏈的第一環,不是驗收,而是合約。
本文不從某個 CLI 指令開始,而是從一套可以放進不同工具與流程的軟體工程方法談起:先宣告邊界,再建立後續可以對照的版本基準。
整篇文章想回答一個問題:如果規格今天被修改,是否能清楚指出哪一個版本曾經被同意、內容是否被動過,以及這次修改是否需要重新驗收?
為什麼自然語言的規格還不夠?
自然語言仍然是規格的重要載體。問題在於,不能單獨依靠一份可以自由修改、缺乏版本與識別碼的 prose 作為治理基準。
同一句話,不同人讀、不同時間讀,甚至同一個 agent 在不同 context 下讀,都可能得到不一樣的理解。當執行者可以高速產出,原本看似不大的模糊,就可能被放大成真正的範圍偏移。
治理需要做的,是在自然語言之外補上明確的需求 ID、non-goals、acceptance criteria、版本化快照與合約指紋,讓後續可以比對、重算,也看得出版本是否被改過。
為了方便後續討論,本文把這兩個方法論動作稱為 DECLARE(宣告) 與 BIND(綁定)。它們並非 Harness Engineering、SDD 或業界既有標準中的固定指令;本文用這兩個名稱分開描述「討論需求」和「建立版本基準」。
動作一:DECLARE —— 先把邊界說清楚
DECLARE 可以理解成把「要做什麼、不做什麼」整理清楚的階段。這裡通常會留下幾類內容:
- Spec(規格文件):描述這個功能要達成什麼、怎麼驗收,以及什麼情況才算完成。
- ADR(Architecture Decision Record,架構決策紀錄):採用這個方案的理由、放棄了哪些選項,以及這個決定帶來哪些約束。
- non-goals(非目標):這次明確不處理的事情,例如不改既有 API、不處理權限、不做效能最佳化。
「不做什麼」,跟「做什麼」一樣重要。
大多數規格只寫要完成的事情,結果 agent(跟人一樣)會在灰色地帶自由發揮。把 non-goals 和 acceptance criteria 一起寫清楚,才能同時畫出「不做什麼」的邊界,以及可以逐條確認的完成條件。
Agent 可以協助整理規格、找出矛盾或提出修改方案,但不應在未經授權的情況下自行擴大工作範圍,也不能自行把修改後的規格視為新的治理基準。DECLARE 的終點,是由有權限的人確認這份內容可以拿來當作這次工作的合約。
從散文規格到可追蹤需求
在採用 SDD(Spec-Driven Development,規格驅動開發)的工作流裡,規格、計畫與任務文件是主要的產物。已確認的需求可以使用固定識別碼標示,例如:
FR(Functional Requirement,功能需求):描述系統必須提供的功能或行為。SC(Success Criteria,成功標準):描述如何從可觀察、可衡量的結果判斷這項工作達成目標。AC(Acceptance Criteria,驗收條件):把需求轉成具體的通過條件,包含正常流程、邊界情況與必要的例外行為。
這些縮寫沒有跨團隊統一的定義;重點是先說清楚各標籤的意思,再在規格、實作與驗收文件中持續使用同一套識別方式。後續的實作與審查準備,都能引用同一批 ID。
這個做法解決的是一個很實際的問題:引導 agent 時看到的完成標準,必須和最後檢查的標準來自同一個來源。 否則文件裡說一套,驗收時又用另一套,合約只是換了一個名字而已。
當工作涉及 public API、schema、資料 migration、lifecycle、concurrency 或跨 feature contract 等風險時,可以把需要被治理的欄位、狀態轉換與不變條件整理成結構化的合約摘要。本文將這類摘要稱為 Contract Manifest,這是方便討論的稱呼,不是業界既有標準;它會連回需求 ID 與相關產物,避免把一大段 prose 直接當成合約。
動作二:BIND —— 建立可驗證的版本基準
DECLARE 完成後,還要決定驗收時拿哪一份規格對照。BIND 是本文用來描述這個動作的抽象名稱:把規格、合約與審查輸入固定成一個可以重新計算、可以對帳的版本基準。
BIND 解決的是「後續到底要對照哪一個版本」,不會讓原本模糊的需求自動變得精確;規格本身是否清楚,仍然要在 DECLARE 階段處理。
數位指紋(digital fingerprint)是辨識內容的方法。實務上,要先定義哪些內容屬於合約,再用固定的排序與序列化方式計算指紋。SHA-256 可以作為常見的計算方式,但 hash 本身不會阻止修改,也不會替內容背書;真正重要的是輸入範圍與計算規則固定。
實作上可以留下幾種互相連結的紀錄:
- 固定版本快照(Artifact Snapshot):記錄某份規格、計畫、任務或合約在這個時間點的內容與內容指紋。
- Contract Manifest:整理已確認需求,以及會影響合約的欄位、狀態轉換與不變條件,並連回需求 ID 與相關產物。
- 審查快照(Review Snapshot):記錄這次審查實際使用的版本快照、合約指紋與治理規則版本。
這些紀錄讓團隊可以直接回答:「這次審查到底是對哪一份規格、哪一個合約做出的?」
指紋先分成兩種就足夠:
- 內容指紋:比對現在看到的內容,是否和建立版本基準時的內容一致。
- 合約指紋(contract fingerprint):只納入治理規則明確指定、會影響需求或合約內容的欄位;對這些欄位固定排序與序列化後計算指紋。這個判斷不應交給 LLM 臨場解讀自然語言。
合約本身是否改變,與哪些下游產物受到影響,是兩個不同問題;後者可以另外透過依賴關係與影響分析(dependency / impact analysis)決定重新驗收範圍。
一個簡單的例子
假設這次要加入帳號刪除功能,規格可以先寫成:
FR-001:使用者可以刪除自己的帳號。AC-001:刪除後不得再使用原 token 存取 API。NG-001(Non-goal):這次不處理管理員代刪帳號。ADR-003:採用 soft delete,依法需要保存的交易資料不得刪除。
DECLARE 是先把這些約定確認清楚;BIND 則建立一個固定版本基準與合約指紋。若 agent 後來把 NG-001 改成「順便支援管理員刪除」,就代表目前的候選內容已經偏離原先綁定的合約版本。在新版合約重新被確認之前,不能直接把原本的 Evidence(證據)或核准結果視為仍然適用。
雜湊不等於真實性:指紋、簽署與授權
數位指紋能回答「內容是否和綁定版本一致」,但不能單獨回答「這份內容是誰提出或核准的」。如果內容與指紋放在同一個可以修改的位置,有權修改的人可能一起換掉兩者,單看 hash 不能分辨來源。
這裡要把三件事分開:
- 數位指紋(fingerprint):辨識內容,確認現在看到的版本是否和綁定時一致。
- 數位簽署(signing):證明掌握對應私鑰的主體簽署了這份內容或指紋。
- Authority(授權):決定這個主體是否真的有權核准、合併、發布或上線。
數位簽章可以驗證這份簽章是由對應私鑰產生,但這把金鑰代表誰,仍需要可信的身分與金鑰管理機制建立對應關係。簽署本身也不會自動授予發布權限;合約是比對基準,不是放行權本身。
實作上,工作中的規格、計畫、任務與合約檔案仍然可以編輯;真正送進審查的,是依照治理規則擷取出的固定版本快照與審查快照。階段核准後,若要保留定稿紀錄,應該新增版本與關聯,而不是覆寫已經被採用的歷史。
最終化階段可以依風險加入額外的內容與來源驗證機制,例如已簽署的 Git commit/tag 或獨立的數位簽章。未來若導入 Git commit/tag 簽章,例如使用 GPG 或 SSH,仍然需要先定義哪些角色可以簽署、哪些金鑰可信,以及簽署結果如何連回合約版本。
有了這個版本基準,後面的 Evidence 與 Attestation 才知道要對照哪一份合約;即使 BIND 成功,也不代表 agent 因此取得 merge 或 publish 的權限。
合約真的需要修改時
不是每一次修改都代表需求變了。改了一條驗收條件的意思,或調整會影響合約的欄位與狀態轉換,屬於實質變更(material change),應該建立新的版本,讓受影響的下游重新驗收。
修正錯字、調整文件排版,或修改不影響合約內容的 metadata,不一定需要讓既有驗收結果失效;但仍應留下新的版本紀錄,並確認已確認需求與合約指紋沒有改變。是否需要重新驗收,仍應由治理規則與實際影響決定。
如果每個標點符號都讓整條鏈失效,團隊很快會覺得治理只是負擔;但只看修改是否位於允許非實質修改的區域也不夠,因為裡面仍可能包含需求內容。
比較實務的做法,是先列出哪些欄位會影響合約指紋,把打包或顯示用的 metadata 另外記錄。這個判斷應該依照事先定義的欄位與治理規則處理,不交給另一個 LLM 臨場判斷。無法明確判定時,一律視為需要重新驗收(fail closed)。
合約要綁死,但要綁對顆粒度。
真的需要修改合約時,就建立新的版本與新的合約指紋,不要直接覆寫那份已經被綁定、也可能已經被拿去驗收的內容。
總結
信任鏈的第一環是合約,因為後續的驗收、獨立確認與放行判斷,都需要知道這次工作原本約定的是什麼。如果一開始連「要做什麼」都沒有固定下來,後面的證據再完整,也可能只是在證明另一件事。
這一篇的重點可以濃縮成三件事:
- 自然語言仍然是規格的重要載體,但需要搭配需求 ID、non-goals、acceptance criteria、版本化快照與合約指紋,才有可對照的治理基準。
- 透過 DECLARE 把邊界說清楚,再用 BIND 建立固定的版本基準;真正影響合約內容的變更,必須建立新版本並重新判斷影響。
- 數位簽署可以補上來源確認,但不等於 Authority;誰能核准、合併、發布或上線,仍然要由授權規則決定。
合約建立後,下一個問題就會浮現:agent 交出東西之後,如何證明它真的符合這份合約? 這就會進入下一篇的主題:可重現驗收與獨立確認,而不是讓 LLM 替另一個 LLM 打分數。
如果回頭仍然無法回答開頭的問題——哪一個版本曾經被同意、內容是否被動過,以及這次修改是否需要重新驗收——表示合約還沒有真正被綁定。
Trust is a chain, not a prompt.
這些原則不依賴特定工具:工具會更換,但「把意圖固定成可驗證的承諾」會一直是自主軟體工程的核心課題。
