diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 1e4c9930d..398f4d845 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,34 @@ +## 2026-05-07 | AwoooP legacy Channel Event 補 completed shadow run 錨點 + +**背景**:Production `/api/v1/platform/runs/list` 回 `total=0`,但系統仍持續有 Telegram 出站訊息與 grouped child alert。盤點後確認:legacy Telegram 出站只寫 `awooop_outbound_message`,使用 soft `run_id`,但沒有對應 `awooop_run_state`;grouped child alert 也只落 `awooop_conversation_event`。結果是 AwoooP Console 有 event / outbound 資料,但 Run Monitor 主列表沒有聚合錨點,看起來像空殼。 + +**本次修補**: +- `channel_hub.py` 新增 `ensure_completed_shadow_run()`: + - 建立 `state='completed'`、`is_shadow=TRUE` 的 mirror run。 + - 使用 `ON CONFLICT (run_id) DO NOTHING`,避免重複事件造成錯誤。 + - 不進入 `pending`,不會被 worker pick up,不會觸發 runtime / Telegram / 修復動作。 +- legacy Telegram outbound 在 `record_outbound_message()` 前,先補 `agent_id='legacy-telegram-gateway'` 的 completed shadow run。 +- grouped child alert 在 `record_grouped_alert_event()` 前,先用 deterministic UUID 補 `agent_id='legacy-alert-grouping'` 的 completed shadow run,並把 inbound event 掛上同一個 `run_id`。 +- 新增 `build_grouped_alert_run_id(project_id, provider_event_id)`,讓同一 grouped child alert 可穩定回查。 +- mirror run 會保存最小 `input_sha256`,讓 strangler 階段也保留資料完整性證據。 + +**驗證**: +- `py_compile apps/api/src/services/channel_hub.py apps/api/tests/test_channel_hub_grouped_alert_events.py` → passed。 +- `ruff check apps/api/src/services/channel_hub.py apps/api/tests/test_channel_hub_grouped_alert_events.py` → All checks passed。 +- `pytest apps/api/tests/test_channel_hub_grouped_alert_events.py apps/api/tests/test_telegram_message_templates.py -q` → 31 passed。 +- Gitea Code Review `#1864` success,CD `#1863` success。 +- CD deploy marker:`4f0d677e chore(cd): deploy 5d38115 [skip ci]`。 +- K8s live image: + - `awoooi-api` → `192.168.0.110:5000/awoooi/api:5d38115d2f95120fe79e742f7e4e3c8ff63cf9b0`。 + - `awoooi-web` → `192.168.0.110:5000/awoooi/web:5d38115d2f95120fe79e742f7e4e3c8ff63cf9b0`。 + - `awoooi-worker` → `192.168.0.110:5000/awoooi/api:5d38115d2f95120fe79e742f7e4e3c8ff63cf9b0`。 +- Production smoke:`/api/v1/health` → 200,`/zh-TW/awooop/runs` → 200。 +- Production `/api/v1/platform/runs/list?per_page=5` 仍為 `total=0`;判讀為上線後尚未有新的 legacy outbound / grouped child alert 經過 API,不是路由錯誤。 +- Production API log 短窗口未看到 `completed_shadow_run`、`outbound_message_recorded`、`grouped_alert_event_recorded`,也未看到 `telegram_outbound_mirror_failed`、`grouped_alert_event_record_failed`、`awooop_run_state` 或 `awooop_outbound` 相關錯誤。 +- 同一窗口另看到既有 `capacity_violation_event_type_valid` check constraint warning(`swap_over_threshold` 無法寫入),與本輪 AwoooP mirror run 無直接關聯,需另排治理修補。 + +判讀:AwoooP Run Monitor 已具備接住 legacy event / outbound 的資料錨點;需要等待下一批真實事件流入才會看到列表不再為空。下一步可處理 `capacity_violation_event` enum/schema 漂移,否則容量治理事件會持續寫入失敗。 + ## 2026-05-07 | AwoooP 人工審批決策寫入 Run Timeline **背景**:AwoooP Run Detail / Action Panel 已把 `waiting_approval` 導到審批頁,審批頁也會在決策後回到 Run Timeline;但後端 `decide_approval()` 只轉 Run state 與寫 audit,Timeline 本身沒有「人工核准 / 人工拒絕」節點。這會讓操作者回到 Run Detail 後,只看到狀態變了,卻看不到是誰在人工閘門做了哪個決策。