Day 28 把失敗縮成可重現的案例。今天把視角拉回整份發行物:測試通過的程式、文件裡的安裝方法,以及讀者實際拿到的版本,是否真的是同一件事?
發布前的驗收不是再看一次綠燈,而是沿著使用者的路徑走一遍。以下流程是 ticket-source-guard 的教學範例,不表示某個公開專案已完成這些測試;狀態名稱也是本系列自訂契約。
第一關:需求能對應到可觀察結果
先用一句話固定範圍:輸入票券來源 URL,依已登錄來源與有效期回傳分類、證據和下一步。不購票、不登入、不保證票券真偽。
每項需求都要有一個可觀察的結果。只寫「避免不安全來源」太模糊;寫成「額外 host suffix 不得命中已登錄來源」,才能固定輸入與預期。
需求 → case_id → 預期狀態 → 實際結果 → 證據
額外 suffix → host-003 → UNCONFIRMED → 待測 → 待測
過期資料 → fresh-002 → NEEDS_REVERIFY → 待測 → 待測
無法讀取 → fetch-001 → 保留未知 → 待測 → 待測
這張表不是裝飾。未測、失敗與通過都要留下,不能把「尚未執行」填成「通過」。
第二關:驗收的是發行物,不是工作目錄
開發目錄可能有未追蹤檔案、舊設定或本機依賴。這些剛好讓測試通過,卻不一定會跟著發行物到讀者手上。
固定 commit 或明確版本,列出檔案清單,再從真正準備發布的內容開始驗收。核對 SKILL.md、references、scripts、測試資料和 README 的路徑,確認文件引用的檔案確實存在。
Agent Skills 規格要求 SKILL.md 有 YAML frontmatter 與 Markdown 內容,也提供 skills-ref validate 的驗證方式。這類檢查能抓出格式與命名問題,但不能證明任務結果正確,更不能證明來源安全。
發行清單
- 固定版本識別
- 必要檔案與檔案雜湊
- 依賴與執行環境
- registry 版本及有效日期
- 驗證紀錄與已知限制
檔案雜湊用來比對內容是否相同,不是作者身分、品質或安全認證。
第三關:在乾淨環境照 README 安裝
不要只在原本的開發環境驗收。選一個沒有舊設定的隔離環境,照 README 的步驟安裝,記錄實際指令、版本與失敗訊息。若安裝會執行外部程式,先檢查內容與權限,不能把「隔離環境」當成沒有風險。
要測的是讀者的入口,不是作者自己記得的捷徑。少一步才能成功,代表 README 有缺口;缺少依賴,代表發行或環境說明不完整。
先做 smoke test:必要檔案能找到、script 能啟動、設定能載入。再執行完整測試與任務型 eval。smoke test 成功不等於所有案例通過。
第四關:走完整任務路徑
script 回傳正確 JSON,只證明其中一層。還要確認 agent 的最後文字沒有把 UNCONFIRMED 寫成「假票」,或把 REGISTERED_SOURCE 寫成「可以放心購買」。
合成 URL
→ 解析與正規化
→ registry 與有效期檢查
→ schema、狀態與退出碼
→ agent 的最後文字
→ next_step 與未驗證限制
拒絕、未知、來源過期與工具失敗都要走到最後。失敗時若仍產生像成功的文字,這是需要驗收的問題,不是可以忽略的例外。
第五關:最後一次改動也要重驗
修正文案可能改變觸發範圍;更新 sources 可能改變分類;重新打包可能漏掉檔案。任何改動都應回到受影響的驗收項目,並核對最後發布內容的版本識別。
只有原封不動的輸出才能沿用相同驗證紀錄。不要先測 A 版,最後發布 B 版,卻仍在 README 寫「已驗證」。
發布判斷要留下理由
阻擋條件可以很簡單:必要檔案缺失、契約案例失敗、來源已失效、文件步驟無法重現,就先不發布。非必要環境尚未測試,則寫清楚支持範圍與未測範圍,不把未知包裝成支援。
今天完成的驗收標準
[ ] 每項需求能對應 case_id 與實際結果
[ ] 驗收版本與最後發行物一致
[ ] 乾淨環境能照 README 完成安裝
[ ] smoke test、script 測試與任務 eval 分開記錄
[ ] 最後文字保留狀態、證據與限制
[ ] 最後修改已重驗,阻擋項目沒有被跳過
參考資料
https://agentskills.io/specification
https://docs.pytest.org/en/stable/how-to/assert.html
明天預告
Day 30 回顧這條從需求到維護的路:哪些東西已經成為可驗證的契約,哪些還需要持續重驗。