Day 12 把 pytest 與 eval 接進 CI,讓分類器、來源 registry 與案例規格成為合併門檻。但測試只保護已寫下的行為;真正執行時,Agent 還需要在 SKILL.md 裡知道每種狀態要怎麼分流、何時安全停止、要向使用者說什麼。
今天把這些失敗政策寫回 Skill 的操作契約。
票務來源檢查不只有成功或失敗。第一版明確分成:
OFFICIAL:命中有效、未過期、未撤銷的來源證據。UNCONFIRMED:URL 完整,但沒有可用正向證據,或證據已過期/撤銷。INSUFFICIENT_INPUT:輸入不足,無法完成分類。CONFIGURATION_ERROR:sources registry、schema 或 loader 損壞。CONFLICT:多筆規則同時命中,或不同來源證據互相矛盾。其中前三個是使用者輸入層的決策結果;後兩個是系統完整性問題。不能把它們全部折疊成 UNCONFIRMED。
在 SKILL.md 加入固定 routing table:
## Routing policy
| Result | May continue to transaction flow? | Required action |
|---|---:|---|
| OFFICIAL | Yes | Continue from the verified entry point and preserve evidence. |
| UNCONFIRMED | No | Stop before login, payment, booking, or data disclosure. Offer the verified first-party path. |
| INSUFFICIENT_INPUT | No | Ask only for the missing URL or context needed to classify. |
| CONFIGURATION_ERROR | No | Stop the workflow, report the internal validation failure, and escalate for registry repair. |
| CONFLICT | No | Preserve the conflicting records and escalate; never choose by file order. |
表格比散落在多段文字裡的「視情況而定」更容易實作、測試與 code review。
OFFICIAL 只回答來源是否通過目前證據規則,不代表:
SKILL.md 必須寫清楚:來源驗證只解鎖後續研究或導向官方入口;任何 wallet-bearing 行為仍需自己的確認與政策。
An OFFICIAL result authorizes only routing to the verified first-party entry point. It does not authorize purchase, booking, sign-in, disclosure, or acceptance of terms.
這句避免 Agent 把「官方」誤解成「可以直接買」。
命中不到證據、紀錄 stale、紀錄 revoked,或 lookalike 風險出現時,都不能繼續登入、填信用卡、建立帳號或上傳文件。
For UNCONFIRMED, stop before any action that sends credentials, personal data, money, credits, or commitments to the observed site.
Safe-stop 不等於只說「不能」。它還要提供下一個可行動作:
不可以把原本的可疑 URL 包裝成「供參考」再讓使用者自己冒險。
如果輸入是:
tickets.example.com/event/1
缺的是 scheme。使用者問題應該是:
請貼完整連結,包含 https:// 開頭。
不要一次追問主辦單位、付款方式、日期、座位區、預算等所有後續資訊。分類器目前只缺一個完整 URL,問題也只應問這一件事。
在 SKILL.md 寫成:
For INSUFFICIENT_INPUT, ask the minimum question that supplies the missing classification input. Do not collect transaction details yet.
當 YAML 壞掉、required field 缺失、日期格式錯誤或規則重疊,Agent 不能對使用者說:
這個網站目前無法確認。
那句話把系統故障錯誤歸因到網站。正確做法是停止使用分類結果,並清楚區分:
來源驗證資料目前無法載入,所以我不能可靠判斷這個連結。我已停止在登入或付款前。
內部 log 可以帶 case id、欄位路徑與錯誤類型,但使用者訊息不應倒出 stack trace 或完整 registry。
雖然 Day 9 loader 會拒絕已知重疊,執行期仍可能遇到:
SKILL.md 的規則必須是:
When evidence conflicts, preserve each record with its source and observed date. Do not average, vote, or choose the first match. Stop and escalate.
「比較新的看起來比較對」不是規則,除非規格明確定義版本與取代關係。
即使結果是 OFFICIAL,後續步驟也要能看見驗證依據:
{
"status": "OFFICIAL",
"checked_url": "https://tickets.example.com/event/1",
"normalized_host": "tickets.example.com",
"evidence": ["source:example-primary"],
"verified_at": "2026-09-01",
"review_after": "2026-10-01",
"next_step": "Continue from the verified official entry point"
}
如果只傳 boolean true,下游無法判斷證據是否過期、來自哪筆紀錄,也無法在使用者詢問時解釋。
SKILL.md 不應寫「來源確認過,所以可用」。它要明確要求:
Evaluate review_after against the explicit execution date. Do not reuse an OFFICIAL result from a previous run without reclassification.
昨天的 OFFICIAL 可能今天就 stale。快取結果可以加速載入,但不能跳過日期與狀態重算。
Machine result 要穩定,使用者訊息可以自然,但兩者不能互相替代。
USER_MESSAGES = {
"OFFICIAL": "這個連結命中目前有效的官方來源紀錄。",
"UNCONFIRMED": "我找不到足夠的官方來源證據,先不在這個網站登入或付款。",
"INSUFFICIENT_INPUT": "請貼完整連結,包含 https:// 開頭。",
"CONFIGURATION_ERROR": "來源驗證資料目前無法載入,我已在登入或付款前停止。",
"CONFLICT": "來源證據互相矛盾,我先不替你選其中一個。",
}
不要讓模型自由發明每種狀態的政策。模板可以依語氣調整,但 safe-stop、原因與下一步不可改變。
在 SKILL.md 加入明確反例:
Never:
- treat a reachable page as official;
- treat TLS/HTTPS as proof of ownership;
- infer official status from logo, design, search rank, ads, or social proof;
- continue because no phishing signal fired;
- downgrade CONFIGURATION_ERROR or CONFLICT to UNCONFIRMED;
- ask the user to proceed at their own risk through an unconfirmed URL;
- bypass source checks because the task is urgent.
負面規則很重要,因為 Agent 面對 deadline 或使用者催促時,最容易自己發明「暫時先繼續」的捷徑。
同一個輸入可能同時有多個問題。用固定順序避免每次得到不同答案:
1. CONFIGURATION_ERROR
2. CONFLICT
3. INSUFFICIENT_INPUT
4. UNCONFIRMED
5. OFFICIAL
先確認分類器的信任根完整,再處理證據衝突,之後才看輸入和命中結果。只有所有更高優先級問題都不存在,才可能是 OFFICIAL。
輸入:
tickets.example.com/event/1
結果:
{
"status": "INSUFFICIENT_INPUT",
"normalized_host": null,
"evidence": ["URL must use http or https"],
"next_step": "Provide a complete HTTP(S) URL"
}
使用者訊息:
請貼完整連結,包含 https:// 開頭。
不進入來源比對,也不收集付款資訊。
輸入:
https://tickets.example.com.attacker.net/pay
結果:
{
"status": "UNCONFIRMED",
"normalized_host": "tickets.example.com.attacker.net",
"evidence": ["no_verified_source_match"],
"next_step": "Open the organizer's verified first-party entry point"
}
使用者訊息:
這個網域沒有命中已驗證來源,我先不在這裡登入或付款。我可以從主辦單位的已驗證入口重新找活動頁。
輸入 URL 即使看起來正常,也不能分類:
source configuration error: overlapping source rules
結果:
{
"status": "CONFIGURATION_ERROR",
"normalized_host": null,
"evidence": ["registry_validation_failed"],
"next_step": "Repair and revalidate the source registry"
}
使用者訊息要承認系統無法可靠驗證,而不是暗示網站有問題。
Day 11 的 cases 要新增:
{"id":"missing-scheme-asks-only-for-url","expect":{"status":"INSUFFICIENT_INPUT","next_step":"Provide a complete HTTP(S) URL"}}
{"id":"stale-source-stops-transaction","expect":{"status":"UNCONFIRMED","next_step":"Open the organizer's verified first-party entry point"}}
{"id":"registry-overlap-is-configuration-error","expect":{"status":"CONFIGURATION_ERROR","next_step":"Repair and revalidate the source registry"}}
{"id":"conflicting-records-never-pick-first","expect":{"status":"CONFLICT","next_step":"Escalate the conflicting source records"}}
Eval 不只看文字,也要驗證 transaction gate:只有 OFFICIAL 可以回傳 may_continue_to_official_entry: true。
{
"may_continue_to_official_entry": true,
"may_login": false,
"may_pay": false
}
這三個欄位拆開,避免下游把「可以打開官方頁」誤解成「可以付款」。
## Source verification gate
1. Validate the registry. On failure, return CONFIGURATION_ERROR and stop.
2. Parse a complete HTTP(S) URL. If incomplete, return INSUFFICIENT_INPUT.
3. Normalize the host and evaluate all matching records.
4. On conflicting evidence, return CONFLICT and stop.
5. On no valid active evidence, return UNCONFIRMED and stop before login, disclosure, booking, or payment.
6. On one valid active record, return OFFICIAL with evidence and dates.
7. OFFICIAL may continue only to the verified entry point. Separate approval is required for every login, disclosure, booking, acceptance, or payment action.
這段是 Agent 的操作順序,也是後續 eval 與 code review 的索引。
[ ] 五種結果彼此不混用
[ ] routing table 定義是否可繼續
[ ] OFFICIAL 不等於購買/登入授權
[ ] UNCONFIRMED 在敏感動作前停止
[ ] INSUFFICIENT_INPUT 只問缺的資料
[ ] CONFIGURATION_ERROR 承認系統驗證失敗
[ ] CONFLICT 保留來源,不選第一筆
[ ] evidence 和日期傳給下游
[ ] user message 不洩漏 registry 或 stack trace
[ ] eval 驗證 status、next_step 與 transaction gate
Day 14 加入 freshness 維護流程:如何定期重驗 evidence、更新 verified_at/review_after,並讓過期來源在無人維護時自動降級而不是永久保持官方。