Commit Graph

19 Commits

Author SHA1 Message Date
Your Name
35fe37c82a fix(api): route direct ollama callers through ordered fallback
All checks were successful
Code Review / ai-code-review (push) Successful in 23s
CD Pipeline / tests (push) Successful in 5m51s
CD Pipeline / build-and-deploy (push) Successful in 3m29s
CD Pipeline / post-deploy-checks (push) Successful in 1m14s
2026-05-19 12:56:13 +08:00
Your Name
5b34877429 feat(awooop): expose drift repeat fingerprint
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 1m17s
CD Pipeline / build-and-deploy (push) Successful in 3m20s
CD Pipeline / post-deploy-checks (push) Successful in 1m13s
2026-05-13 07:36:21 +08:00
Your Name
c4854bb355 fix(ai): isolate heavy Ollama workloads from GCP alert lane
All checks were successful
CD Pipeline / tests (push) Successful in 54s
Code Review / ai-code-review (push) Successful in 10s
CD Pipeline / build-and-deploy (push) Successful in 3m19s
CD Pipeline / post-deploy-checks (push) Successful in 3m12s
2026-05-05 23:06:07 +08:00
Your Name
b1ef05fa8c feat(ollama): ADR-110 GCP 三層容災架構(GCP-A → GCP-B → Local → Gemini)
Some checks failed
Code Review / ai-code-review (push) Successful in 50s
CD Pipeline / tests (push) Failing after 1m14s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
## 變更摘要
- Primary: http://34.143.170.20:11434 (GCP-A SSD, 9x 載速 + 2x 推理)
- Secondary: http://34.21.145.224:11434 (GCP-B SSD)
- Fallback: http://192.168.0.111:11434 (M1 Pro Local HDD,最後防線)
- 廢止 ADR-105「111 唯一鐵律」,新建 ADR-110

## 核心改動
- config.py: 新增 OLLAMA_SECONDARY_URL;validator 加 GCP IP 白名單(34.143.170.20, 34.21.145.224)
- ollama_failover_manager.py: 三層 Ollama 決策矩陣;並行健康檢查三台;health_111 → health_gcp_a
- ollama_health_monitor.py: host label 萃取改為通用版(支援 GCP 公網 IP)
- failover_alerter.py: 故障/恢復主機動態顯示,不再硬編碼「Ollama 111 (GPU)」
- ollama_auto_recovery.py: notify_recovery 改為 ollama_gcp_a;recovered_host 動態
- k8s/awoooi-prod: configmap + deployment + network-policy 同步更新(egress 加 GCP /32)
- 服務層: 10 個服務檔案硬編碼 192.168.0.111 改為讀 settings.OLLAMA_URL
- 測試: URL 常數更新,新增三層容災場景,GCP IP 白名單驗證測試

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 22:49:23 +08:00
Your Name
54d60d04f5 feat(drift+target): P0.1+P0.2+P0.3 三修 — drift 分頁分類 + AI 推薦 + target 追 trace
統帥三問決議:全做;AI 推薦 0.85 門檻純顯示不自動;先查 aol 再修

## RCA: awoooi-service 失敗來源
- /api/v1/aiops/kpi 顯示過去 24h 有 1 筆 playbook_executed actor=approval_execution status=failed
- grep codebase: 無任何程式碼寫死 awoooi-service(只有歷史 comment)
- 最可能源: alert_rule_engine._extract_vars 從 labels.service 取值當 Deployment 名
- cf5050c/4f2e122(2026-04-18)已修 NEMOTRON 幻覺雙路徑;本次修第三條路徑

## 修復
### P0.3a alert_rule_engine._extract_vars
- labels.service 降級:-service 結尾先剝 suffix 視為 base name
- match_rule 回傳新增 target_source 欄位追 trace
- 下次 awoooi-service 復發可直接看來源(label.service(stripped) 等)

### P0.3c approval_execution._log_aol_started.input
- 補 parsed_target/operation/namespace 欄位
- 未來 aol 查 failed 可直接看 target,無需推敲

### P0.1 telegram_gateway._send_drift_diff_detail
- 分頁(10 項/頁)取代一次洗版 30 項
- header 3 桶分類計數: 人工高風險 / 一般修改 / K8s 自動
- 底部 ⬅️/➡️ 分頁按鈕(callback: drift_view_page:{report_id}_{page})
- security_interceptor INFO_ACTIONS 加 drift_view_page 白名單

### P0.2 drift_narrator recommendation
- LLM prompt 加 recommendation 欄位(action/confidence/reason)
- action ∈ {adopt, revert, ignore, investigate}
- 卡片頂部顯示「🎯 AI 建議: 回滾 (85%) — reason」
- LLM 失敗走 _fallback_recommendation(規則式依 intent 對應)
- 卡片 diff_summary 上限 500 → 1500 字容納推薦 + narrative + items
- 統帥指令:純顯示不自動執行(門檻 0.85 保留未來)

## 驗證
- 90 個 pytest test 全過(drift + rule_engine + approval_execution)
- 5 檔 AST syntax check 過

## 下次驗收
1. 下次 drift 觸發 → 卡片頂部有「🎯 AI 建議」
2. drift_view 按下 → 3 桶分類 header + ⬅️/➡️
3. awoooi-service 若復發 → automation_operation_log.input.parsed_target 直接查

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 04:04:13 +08:00
OG T
b0d560dbb3 fix(drift-narrator): shortener 用 replace — 包容 LLM 加 'Resource/Name:' 前綴幻覺
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 10m50s
2026-04-18 下午(台北時區)— ogt + Claude Opus 4.7

Round 4 LLM 自己在 field 前加資源識別符:
  'Deployment/awoooi-web: spec.template.spec.containers'
導致 startswith 模式 shortener 失效(前綴不在開頭)。

防禦式修法: startswith 不中 → 改用 replace 清除任何位置的前綴。
結果:
  'Deployment/awoooi-web: containers' 

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 18:12:15 +08:00
OG T
b63aed72df fix(drift-narrator): 砍 spec.template.spec. 前綴 — 修 Telegram 自動換行醜陋排版
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m1s
2026-04-18 下午(台北時區)— ogt + Claude Opus 4.7

統帥實彈三輪視覺回報: 字段名 'spec.template.spec.volumes' 共 24 字元,
加上 emoji+': '+summary 超過 Telegram <pre> 視覺寬度,自動換行
造成 emoji 與 field name 斷開、單獨成行的醜狀。

修復: _shorten_field_path() 砍 3 種常見前綴:
  - 'spec.template.spec.' → ''
  - 'spec.template.' → ''  (後備)
  - 'spec.' → ''  (後備)

效果對比:
  前: '🟡 spec.template.spec.affinity.podAntiAffinity.preferredDuringS: [清單 3 項]'
  後: '🟡 affinity.podAntiAffinity.preferredDuringS: [清單 3 項]'

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:10:20 +08:00
OG T
f3960f36d2 fix(drift-narrator): fallback 強化 — 標註 K8s 預設值補齊 + 可操作數獨立計算
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 10m37s
2026-04-18 下午(台北時區)—— ogt + Claude Opus 4.7 (1M)

統帥實彈測試回報: 卡片顯示「securityContext: (未設) → {物件 0 欄位}」毫無意義。

根因: _fallback_items 對「K8s controller 自動補齊空物件」的噪音
     誤當成真實變更輸出。且「還有 29 項」數字包含白名單 + trivial。

修復 3 項:

1. _is_trivial_drift() 新判定函數
   None/空字串/{}/[]/false/0 等互相視為「無實質變更」
   捕捉 K8s controller 自動補齊場景

2. _summarize_item() 替代原本 smart_shorten
   - trivial → "K8s 預設值補齊 (無實質變更)"
   - None → value → "新增 xxx"
   - value → None → "已刪除 (原: xxx)"
   - 其他 → "from → to"

3. _fallback_items() 改進
   - 按 level 排序 (HIGH 優先)
   - 白名單 + HPA allowlist 先過濾

4. _count_nontrivial_drift() + Telegram 呈現
   - 新增「可操作」計數 (去掉白名單 + trivial)
   - 「還有 N 項」用可操作數,不會誤導
   - items 為空時顯示「全為白名單或預設值補齊」

預期效果:
  之前: "... 還有 29 項" (其實只 1 個是真實 drift)
  現在: "... 還有 0 項" 或 "(全部為白名單或預設值補齊)"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:29:49 +08:00
OG T
1606093dd2 fix(drift-narrator): 兩個 hotfix — NEMOTRON wrapper 解析 + tags asyncpg 型別
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
2026-04-18 下午(台北時區)—— ogt + Claude Opus 4.7 (1M)

Live-fire test (report_id=80a34b58) 暴露兩個 bug:

## Bug 1: LLM JSON 被 NEMOTRON wrapper 吞掉
根因: openclaw.call() 經 NEMOTRON 路由時強制回 {description,...} 結構,
     我的 prompt 要 {narrative, items} 無法穿透。
     (同 1ff3405 早前碰過的 JSON 裸奔問題根源)

修復: 三路 fallback 解析
  - Path 1: 直接我們的 {narrative, items}(Ollama 或 LLM 守規矩)
  - Path 2: NEMOTRON wrapper,description 巢狀 JSON 含我們結構
  - Path 3: description 是純敘述 → 當 narrative + Python fallback_items

## Bug 2: tags 參數 asyncpg DataError
根因: 傳 '{drift,type4d,llm_summary}' 字面量字串,asyncpg 要求 Python list
      '(a sized iterable container expected (got type str))'

修復: tags 改傳 ['drift','type4d','llm_summary'] Python list,移除 CAST AS text[]
     asyncpg 自動推斷 text[]

Live-fire 結果驗證:
  - narrative  生成(fallback path)
  - items ⚠️ 只 1 筆(NEMOTRON 未吐我們結構)
  - DB write  tags 型別錯
  - Telegram  送出(雖 fallback 內容但視覺 OK)

本 commit 後預期:
  - LLM 回應走 Path 2/3 → narrative + Python fallback items(5 筆 smart summary)
  - DB write 成功 → automation_operation_log + ai_collaboration_trace 皆有記錄
  - 若 LLM 未來學會走 Path 1(給我們 {narrative, items}),自動升級

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:26:17 +08:00
OG T
a156566b17 feat(drift-narrator): ADR-090-C L4 稽核閉環 — notification_formatted op 入庫
Some checks failed
CD Pipeline / build-and-deploy (push) Successful in 10m47s
run-migration / migrate (push) Failing after 14s
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>
2026-04-18 16:04:23 +08:00
OG T
fb88512fcb fix(drift-narrator): B 方案 LLM 驅動智能摘要 — 徹底消滅 str()[:30] 暴力截斷
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
2026-04-18 下午(台北時區)—— ogt + Claude Opus 4.7 (1M)

根因:
_format_drift_summary() 對 dict/list 型別的 git_value/actual_value
直接呼叫 str()[:30] 暴力截斷,產生像 "[{'name': 'repair-ssh-key', 's"
這種亂碼掉半個 dict key 的亂七八糟輸出,徹底違背「AI 自主化」原則。

B 方案架構決策:
「捨棄 Python 寫死的字串解析邏輯。將原始 Config Diff 結構直接作為
Context,餵給 Hermes/NemoTron,利用 prompt 規定輸出格式,讓 LLM 自己
消化並輸出包含紅黃燈標示的 Top 5 人類易讀摘要。」

實作:
1. _NARRATIVE_PROMPT 重寫 — 要求 LLM 回傳 {narrative, items[]} JSON
   - drift items 以 JSON serialize 餵進 prompt(保留 200 字 context)
   - items 限 5 筆,HIGH 優先
   - summary 30 字繁中口語(非技術 repr)
2. _generate_narrative_and_items() 新方法 — 解析 LLM JSON 並驗證結構
3. _format_drift_for_llm() 新方法 — 結構化 JSON 給 LLM(取代舊 str 版)
4. _render_telegram_body() 新方法 — 組裝乾淨的 Telegram 卡片
   範例輸出:
     🤖 AI 研判
     <LLM 4-5 行敘述>

     📊 漂移明細 (HIGH: 1 | MEDIUM: 29)
     🔴 spec.template.spec.volumes: 新增 2 項 repair-ssh-key 掛載
     🟡 spec.template.spec.serviceAccount: (未設) → awoooi-executor
     ... 還有 27 項 (按 🔍 查看 Diff)

5. Fallback 強化 — _smart_shorten() + _fallback_items()
   LLM 失敗時用型別感知的 Python 摘要(dict/list 顯示大小,不暴力 repr)

移除:
- _format_drift_summary() — 舊的暴力截斷實作
- _generate_narrative() — 只回 string 的舊介面

保留:
- _fallback_narrative() / _format_intent_summary() — 仍有用
- Redis 快取 / trigger 條件 / DB update — 邏輯不變

MVP 階段:
本 commit 只改視覺呈現,沒動 automation_operation_log / ai_collaboration_trace
稽核寫入。等 Telegram 視覺驗證 OK 後再做 Phase 2 加入 DB 稽核。

相關:
  - feedback_ai_autonomous_direction.md 北極星原則
  - 1ff3405 今早的 JSON 裸奔 hotfix(只修了 narrative,沒修 items)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:54:16 +08:00
OG T
1ff3405755 fix(drift-narrator): 修復 JSON 裸奔 — 從 NEMOTRON 回傳解析 description 欄位
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 10m44s
根因:openclaw.call() 經 NEMOTRON 路由後強制輸出 JSON(NEMOTRON_SYSTEM_PROMPT 鐵律)
      但 _generate_narrative 期待純文字 → JSON 整包吐到 Telegram <pre> 區塊裸奔

修復:收到 text 後先嘗試 JSON 解析
      - 成功 → 按優先順序取 description / action_title / reasoning
      - 失敗(非 JSON)→ 原文使用(向下相容 Ollama qwen 純文字回傳)

效果:Telegram Config Drift 卡片顯示繁中人話摘要,不再吐原始 JSON

2026-04-17 ogt + Claude Sonnet 4.6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 01:08:32 +08:00
OG T
58d9c0637a fix(drift): drift_narrator 改用 OpenClaw AI Router — 修復「研判原因」空白
根因:drift_narrator_service.py 的 _generate_narrative() 直接呼叫
      Ollama httpx (192.168.0.111:11434),繞過 AI Router,無 fallback。
      192.168.0.111 為死亡 IP → httpx 連線失敗 → 降級 fallback_narrative()
      → fallback 中 interpretation.explanation 存在但顯示層截斷 → 空白

修復:改用 get_openclaw().call(prompt),統一走 AI Router
      同 drift_interpreter.py 的修法(d952435)
      移除 unused httpx import

2026-04-17 ogt + Claude Sonnet 4.6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 13:28:16 +08:00
OG T
eda0cfd034 fix(adr075): drift 通知改用 send_drift_card,補齊所有呼叫點
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m13s
- drift.py: 移除死碼 send_text(),改由 narrate_and_notify() 統一發卡片
- drift_narrator_service: _send_telegram() 改呼 send_drift_card() 帶四顆按鈕
- webhooks.py /alerts 路徑: 補傳 alert_category 啟用動態按鈕

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 20:20:47 +08:00
OG T
f2c18c4e63 feat(D1): models.json 集中化 — ADR-067 五大 Ollama 應用 hardcode 消除
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m56s
- models.json v1.3.0: providers.ollama.models 新增 9 個 purpose keys
  (drift_summary/drift_intent/log_anomaly/nemoclaw/playbook_draft/
   code_review/embedding/rag_generate/image_analysis)
- drift_narrator_service: NARRATOR_MODEL → get_model("ollama","drift_summary")
- drift_interpreter: MODEL → get_model("ollama","drift_intent")
- log_summary_service: SUMMARY_MODEL → get_model("ollama","log_anomaly")
- local_code_review_service: _MODEL_OLLAMA → get_model("ollama","code_review")
- image_analysis_service: _MODEL → get_model("ollama","image_analysis")
- decision_manager: nemoclaw + playbook_draft 兩處 → get_model()
- embedding_service: get_embedding_service() factory → get_model("ollama","embedding")
- knowledge_service: OllamaEmbeddingService(model=...) → get_model()

所有模型名稱現在統一由 models.json 管理,修改模型只需改一個檔案。
LOGBOOK 更新:D1 完成 + B2 已完成確認

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 20:45:53 +08:00
OG T
b24fae313e fix(drift_narrator): 補寫 narrative_text 到 DB + drift_repository.update_narrative
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
2026-04-10 11:06:50 +08:00
OG T
1c4bdedc64 fix(drift_narrator): send_text → send_notification + DriftLevel case fix
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m43s
2026-04-10 10:48:36 +08:00
OG T
68e9ef5d26 fix(drift_narrator): DriftItem.severity → drift_level.value 欄位名稱修正
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
2026-04-10 10:24:41 +08:00
OG T
89015d4527 feat(phase30): Drift 報告 AI 人話摘要 (ADR-067)
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
- 新增 DriftNarratorService — qwen2.5:7b-instruct (Ollama 111)
  - 觸發條件: high >= 1 or medium >= 3(HPA replicas 白名單)
  - Redis 快取: drift_narrative:{report_id} TTL 1h
  - LLM 失敗時 graceful fallback 結構化文字
- drift.py _analyze_and_notify: 接入 narrator(Phase 30 標記)
- Migration: drift_reports.narrative_text TEXT (已在 prod 執行)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 01:37:43 +08:00