Day 19 放手跑完三輪,它交回三份檔案、七條 oracle 判了三條 FAIL,還附上 needs-spec 與 inconclusive。問題是這些判定全出自它自己的嘴。今天替每一筆發現標一個信心分數,把「它說有問題」換算成「你要不要親自看一眼」。
一輪探索交回來的東西是混在一起的:pass、fail、needs-spec、inconclusive、順手撿到的異常。你沒有時間逐筆讀完再決定要不要處理。
沒有分數只剩兩個選擇,兩個都不能用。全部自己看,Day 19 的放手等於白放;全部相信它,issue tracker 兩週就被塞爆。
分數的工作是排序與分流:哪些高到可以自動送去獨立驗證,哪些進人工佇列,哪些只留紀錄不往下走。
還有一個副作用同樣重要。要算分就得列出憑哪幾個因子,這逼它把「我覺得是 bug」拆成「複現幾次、命中哪條 oracle、證據齊不齊」。結論不能吵,憑據可以吵。Day 24 的閘門也要有這個數字才設得出門檻。
現象先講。 2026-07-30 那輪跑完,交回 8 個候選,每一筆都自帶信心分數。問題出在那些分數是它自己給的。當天的 run log 有這麼一句:
- "subagent 反覆把 typo 打 confidence 0.95;分數以 references/confidence.md 重算,未採信。"
UI 拼字錯誤,它打 0.95。照它的話全部往下送,那一輪會有一張「Massage 拼錯」的單躺在 tracker 裡,跟 SQLi 登入繞過排在一起。
那就全部驗一次? 算一下成本。驗一筆的意思是另外開一個乾淨的 subagent、照步驟從零重現一遍(那是 Day 23 的主題)。這輪的 6 個候選共用一個這樣的 subagent,實測吃掉 103,665 tokens,而 budget.max_tokens_per_run 是 200,000,主迴圈還沒計量。多驗兩筆不是驗不動,是明知它們會被 Day 24 那道開單前的閘門擋下,還要先付一次重現的錢。
篩選的做法是先算分、再對門檻。confidence.min_to_file 預設 0.7,C-07 拼字重算後 0.45、C-08 按鈕重疊 0.30,兩筆都不送驗,直接判 hold 進人工佇列。校準表裡它們記的是 not-sent,不是 null:沒送驗跟送了沒結果是兩件事,混在一起之後就算不出漏報率。
grep -E '^findings|^gate_passed|^issues_opened:|^held_for_human' output/runs/2026-07-30.yaml
findings: 8 # hunter 候選 6(confidence high)+ 2 筆未達門檻留人判
gate_passed: 6
issues_opened: 6
held_for_human: 2 # C-07 文案拼字、C-08 按鈕重疊
(log 裡的 hunter 是那輪負責去找 bug 的角色,Day 22 才會正式打造它,這裡先當成「Day 19 那種自主探索的一輪」看就好。)
8 個候選送驗 6 個,6 個全數 confirmed,開出 6 張單,2 筆留給人,沒有一張拼字單進 tracker。
關鍵在中間那一步:0.95 是怎麼變成 0.45 的。下一節就是那張重算的表。
規則的真檔是 references/confidence.md。它刻意不綁在任何一支 skill 底下,是一份共用的計分表:後面幾天負責打分、蓋章、設開單門檻的角色,讀的都是同一份。動手算之前先把邊界劃清楚:這個分數不是「是不是 bug」的判決,蓋章要等 Day 23 的獨立重現,它只回答這筆該不該自動往下走。
總分 0 到 1,五個因子相加。獨立複現次數配分最重(4 次以上 0.35、3 次 0.25、2 次 0.15、只有 1 次 0),因為重複是唯一不靠判斷就拿得到的證據。oracle 強度次之:不需要外部規格就成立的那幾條(內部一致性、API 對 UI、無 console error)給 0.25,要引規格文件的 0.20,只能訴諸使用者期待與領域常識的 0.10。證據完整度看截圖、network、console、重現步驟齊不齊,全齊 0.20、缺一類 0.10、只有文字描述 0。分類確定性 0.10,條件是判成 product-bug 且 basis 指得到具體證據檔。跨情境一致 0.10,指跨身分、跨環境、跨瀏覽器都中。
再往上壓兩個調整項與三條封頂。產品自動回復、終態正確的扣 0.20,因為使用者實際看不到錯誤結果;只在單一環境出現、未再驗證的扣 0.10。封頂先於加總:verdict 是 needs-spec 或 inconclusive 直接封 low,湊不出重現步驟封 low,只出現一次又沒有跨情境佐證封 med。最後 0.7 以上是 high、0.4 到 0.69 是 med、其餘 low,門檻讀 config/sdet-config.yaml 的 confidence.min_to_file。
output/calibration.yaml 修分數打分當下就在 output/calibration.yaml 記一列:id、run、fingerprint、predicted、score,再留 verifier_verdict 與 human_verdict 兩個空欄等回填。前者由 Day 23 的盲驗寫入,後者由人複核後補。
讀法只有兩條。打 high 卻常被打槍,是系統性過度自信,該調高門檻或降低單次複現的配分;後來確認是真 bug 的卻常被壓成 low,是太保守,漏報成本更高。
本專案實跑到現在有 10 列:6 筆 high、2 筆 med、1 筆 low、1 筆沒打分。verifier_verdict 回填了 8 筆 confirmed、2 筆 not-sent,human_verdict 十筆全是 null。
這份表現在還校準不了什麼,而且盲點就寫在資料裡:那 2 筆標 not-sent 的,正是 med 與 low 那兩筆,因為沒過門檻所以根本沒送盲驗。只驗高分的那些,你算得出 precision(6 筆 high 全部 confirmed),永遠算不出 recall。被壓低的那些到底有幾筆是真 bug,這份表答不出來。要修掉這個偏誤,得定期抽一批 med 與 low 補送盲驗,讓低分那一格也長出資料。

門檻擋掉的不只是雜訊,也擋掉了「知道自己漏了什麼」的機會。
一輪探索交回一批候選,每一筆先用五個因子算出 0 到 1 的分數,再套調整項與封頂規則,最後拿去對 confidence.min_to_file 分流:高的自動送去獨立重現,中間的進人工佇列,低的只留紀錄。分數在打的當下就寫進 output/calibration.yaml 的 predicted,等重現結果與人的複核回填另外兩欄,累積下來的落差再反過來調配分與門檻。
一輪探索交回候選
│
▼
五因子加總 → 調整項 → 封頂規則
│
▼
對門檻 min_to_file 分流
│
┌───────────────┼───────────────┐
▼ ▼ ▼
≥ 0.70 0.40-0.69 < 0.40
high med low
送獨立重現 進人工佇列 只留紀錄
│ │ │
└───────────────┼───────────────┘
▼
calibration.yaml 寫入 predicted
│
▼
回填 verifier_verdict / human_verdict
│
▼
比對預測與實際 → 調配分、調門檻
│
└──────► 回到第一步
分數是分流不是判決,它決定誰先被看,不決定誰是 bug。分數本身也要能被拆開,說不出憑哪幾個因子的分數,跟 subagent 隨口打的 0.95 沒有差別。而這條線最後一段是回填,沒有回填就沒有校準,配分永遠停在第一版。而本專案的 human_verdict 現在十筆全空,所以這條迴路目前只跑完了前半段。
分數解決的是「哪一筆先看」。但同一個 bug 在四輪裡各被撿到一次,它會給你四個 high,分數本身分不出那是四個問題還是同一個問題的四次觀察。
明天處理這件事:用指紋把同一個 bug 的不同次觀察算成同一個字串,重複的併進舊單而不是開第二張;再拉一份誤報名單,把已經有人拍板不算 bug 的症狀壓下去,別讓它每一輪都回頭再報一次。
calibration.yaml 現在的處境calibration.yaml 這個做法的出處references/confidence.md - 配分表、調整項與封頂規則的真檔state-templates/calibration.example.yaml - 校準表的欄位定義