taiwan-hospital 的總數檢查是我寫的:9/20 實測 API 回 37,133 筆,我就把 37,133 寫死成基準。院所每天都有開業和歇業,這個數字不可能不動。9/29 排程跑出來是 37,175,health-check 開始變紅。
2026-10-02 我重跑 check-counts.py,單獨一行失敗:expected 37133, got 37175。資料沒壞,欄位沒少,API 也回 success: true,壞的是我的檢查把「會漂移的數字」當成「不能變的數字」。倉庫裡 issue #8 從 9/29 開著,排程 run 9/29、9/30、10/1、10/2 都是紅的。
順帶一個更糟的問題:workflow 裡某一步失敗,後面的 invoice、實測日、URL 檢查會被跳過。紅燈不只是吵,還會遮住其他問題。
| 情況 | 處理 |
|---|---|
| 總數偏離基準在 ±5% 內 | OK |
| 總數偏離基準超過 ±5% | WARN,提醒重測更新文件 |
success 不是 true、必要欄位缺失 |
FAIL |
| 總數低於 30,000 | FAIL,視為資料異常驟降 |
| 最後一頁筆數對不上該頁自己的 total | FAIL,分頁不完整 |
同一批修正還有兩件小事:每個檢查步驟加 if: ${{ !cancelled() }},一步失敗不再跳過其他步驟;check-urls.py 把文件裡的 offset=N 說明代入 offset=0,不再回 400 誤報。2026-10-02 push 後的 run 全部步驟通過。
push 的 run 是綠的,但 10/2 的排程 run 在 counts 步驟失敗。重現之後發現是我新加的「最後一頁完整性」有毛病:我先抓第一頁拿 total,再用這個 total 算最後一頁該有幾筆。兩次請求之間資料已經變了,預期 177,實得 178。
下面這段可以重跑,每次都抓兩個 total 來比。2026-10-03 連跑三次,結果是 37,177 對 37,178、37,178 對 37,178、37,178 對 37,177,最後一頁筆數分別是 178、178、177。同一個 API 在幾秒內會在 37,177 和 37,178 之間跳。
python3 - <<'PY'
import json, urllib.request
BASE = 'https://info.nhi.gov.tw/api/iode0010/v1/rest/datastore/A21030000I-D2100G-001'
def get(offset):
req = urllib.request.Request(f'{BASE}?limit=1000&offset={offset}', headers={'User-Agent': 'Mozilla/5.0'})
return json.loads(urllib.request.urlopen(req, timeout=60).read())['result']
first = get(0)
total = first['total']
last_off = (total - 1) // 1000 * 1000
last = get(last_off)
print('第一次 total', total, '最後一頁自己的 total', last['total'])
print('最後一頁筆數', len(last['records']), '預期(用第一次 total)', total - last_off, '預期(用自己的 total)', last['total'] - last_off)
PY
修法是最後一頁的筆數只跟「那一頁回應自己的 total」比;兩次 total 相差超過 50 才當成異常。這是 0.8.5,2026-10-03 push 後的 run 通過。這個修正後來被排程 run 驗證了:2026-10-03 16:14 UTC 的排程 run 全部步驟綠燈,issue #8 自動關閉(https://github.com/tahodev/baodao-skill/actions/runs/37136136935)。