Day 28 我寫了「26 次裡有 15 次紅燈,沒有逐一追原因」。這次補上。從 Actions API 把 15 個紅燈排程 run 的失敗步驟全部撈出來,再對照 CHANGELOG 和 issue,看每一次到底是什麼壞掉。寫稿時(2026-10-06 03:44 KST)最新的排程 run 仍是 10/4 的 #77,綠燈。
runs 端點只給整個 run 的結論,失敗的是哪個步驟要再打 /runs/{id}/jobs。腳本如下:
import json, urllib.request, urllib.error
def get(u):
try:
return json.load(urllib.request.urlopen(u, timeout=30))
except urllib.error.HTTPError as e:
raise SystemExit(f'GitHub API {e.code}: {e.read().decode()[:100]}')
B = 'https://api.github.com/repos/tahodev/baodao-skill/actions'
runs = get(B + '/runs?event=schedule&per_page=100')['workflow_runs']
for r in sorted(runs, key=lambda r: r['created_at']):
if r['conclusion'] != 'failure':
continue
jobs = get(f"{B}/runs/{r['id']}/jobs")['jobs']
bad = [s['name'] for j in jobs for s in j['steps'] if s['conclusion'] == 'failure']
print(r['created_at'][:10], r['run_number'], r['head_sha'][:7], bad)
2026-10-06 03:44 KST 實測輸出(共 15 行,列出前後各幾行):
2026-09-09 1 c49eedc ['Check URLs in SKILL.md files']
2026-09-16 11 fcfa13f ['Check URLs in SKILL.md files']
2026-09-20 36 e797d51 ['Re-verify headline record counts']
2026-09-25 41 e797d51 ['Re-verify headline record counts']
2026-10-02 63 c97ec91 ['Re-verify headline record counts']
15 次的失敗步驟都只有一個,沒有同時壞兩個的:9/9 到 9/16 的 5 次是 Check URLs in SKILL.md files,9/20 到 10/2 的 10 次是 Re-verify headline record counts。
Re-verify headline record counts 這步會拿線上資料的總筆數,跟腳本裡寫死的基準數比。下面是這 10 次對照 CHANGELOG 的結果:
| 日期(排程 run 的 UTC 日期) | 次數 | 失敗的檢查 | 修法 |
|---|---|---|---|
| 9/20 到 9/25 | 6 | 停車場場數 exact-match | 0.8.2:改成 ±5% 的 WARN |
| 9/29 到 10/1 | 3 | 醫院診所總數寫死 37,133,實際 37,175 | 0.8.4:總數漂移改 ±5% WARN |
| 10/2 | 1 | 醫院診所最後一頁:預期 177,實得 178 | 0.8.5:用最後一頁自己的 total 比對 |
這 10 次裡,9/20 到 9/25 的 6 次是同一個 commit(e797d51),倉庫沒有任何變動,紅燈連續六天,每天都是同一件事:公開資料在漂,我的基準數不漂。9/29 起的醫院診所也一樣:紅了三天才改成 ±5%,改完的隔天又因為同一份資料的最後一頁筆數差 1 筆再紅一次。每個修正都只處理眼前看到的那個數字,下一個會漂的數字還在後面。
整理出來的原則只有一條:線上資料的總筆數不是常數,不能用 == 比。現在 check-counts 的分法是:總數在 ±5% 以內不報,超過報 WARN,只有「回應成功旗標失敗、欄位缺失、總數掉到 3 萬以下、最後一頁筆數跟自己的 total 對不上」這類結構性問題才算 FAIL。
9/9、9/10、9/12、9/13、9/16 這 5 次失敗的步驟是 URL 檢查,issue #1 到 #3 的標題寫的是「lint or dead URL」。當時的 run log 我沒有逐一打開,所以這 5 次到底是哪個網址、什麼原因,我沒有證據可以寫。能確定的只有失敗步驟的名字,和 9/16 之後的排程 run 裡 URL 檢查沒有再失敗過。
這個腳本一次最多打 1 + 15 次 API,未登入每小時只有 60 次額度。我在寫腳本前先用 curl -s https://api.github.com/rate_limit | jq -c .resources.core.remaining 看還剩幾次(當時是 49),跑完剩 38。腳本遇到 HTTPError(例如額度用完回 403)會印出狀態碼和訊息然後停下來,不會印一半的結果。