feat(drift-narrator): ADR-090-C L4 稽核閉環 — notification_formatted op 入庫
2026-04-18 下午(台北時區)—— ogt + Claude Opus 4.7 (1M)
架構鐵律執行:
「沒有被記錄的 AI 決策,就等於沒有發生過。」
drift_narrator 每次呼叫 LLM 生成摘要,必須完整寫入
automation_operation_log + ai_collaboration_trace,形成 L4 稽核 + RLHF 語料。
本 commit 兩件事:
1. apps/api/migrations/adr090c_notification_formatted_op_type.sql
- 擴充 automation_operation_log.operation_type CHECK 加 'notification_formatted'
- DROP + ADD CONSTRAINT idempotent 模式
- 已用 awoooi(表 owner)apply 進 prod 驗證通過
2. apps/api/src/services/drift_narrator_service.py
- 新增 _log_ai_action_to_db() 負責 DB 稽核寫入
- 在 _generate_narrative_and_items() 結尾(success / fallback 都寫)呼叫
- automation_operation_log:
* operation_type='notification_formatted'
* actor='drift_narrator'
* input = {report_id, namespace, counts, items_scanned}
* output = {narrative, items, items_count}
* duration_ms, tags=['drift','type4d','llm_summary']
* parent_op_id 查詢 alert_fired 鏈路(未來 drift → alert 關聯)
- ai_collaboration_trace:
* agent='drift_narrator', model=provider (ollama / nemotron / 等)
* prompt(限 8000 字)+ response(JSONB)
* accepted = LLM JSON 解析成功 flag(未來 RLHF 訓料金礦)
- 錯誤處理: DB 寫入 try/except 包住,永不破壞 Telegram 通知主流程
P2.4 事件關聯:
- SELECT parent op via input->>'report_id' 或 'drift_report_id'
- 若找到則綁定 parent_op_id(形成 alert_fired → notification_formatted 追溯鏈)
- 目前 drift 本身不經 alert_fired,parent 為 NULL(等未來鏈路接通)
P2.5 RLHF 語料:
- ai_collaboration_trace.accepted=true 的紀錄即為「LLM 解析成功」樣本
- 未來統帥按 Telegram [✅ 採納變更] / [⏪ 回滾] 時,對應 trace 也可更新
outcome flag,形成完整 Human-in-the-loop 語料
技術細節:
- get_db_context() auto-commit(src/db/base.py:128),無需手動 commit
- prompt 最長 8000 字(一般 drift 約 2-3k)
- raw_response 保留前 500 字在 trace.response JSON 中
相關:
- feedback_ai_autonomous_direction.md L4 北極星
- feedback_secrets_leak_incidents_2026-04-18.md L1-L4 分層
- ADR-090 11 張神經網路表
- commit fb88512(B 方案視覺層)
IDE 可能顯示 src.db.base 找不到 —— 那是誤報(drift_repository.py 用同一條路徑)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>