Commit Graph

906 Commits

Author SHA1 Message Date
OG T
78a8d3dfa5 fix(api): ansible 控制節點加白名單驗證,防環境變數繞過 (Re-Review Important)
首席架構師 Re-Review 指出: ANSIBLE_CONTROL_HOST 來自環境變數 (ConfigMap),
若 ConfigMap 被篡改可繞過 SSH_TARGET_WHITELIST。
在 _execute_ansible() 開頭加 validate_ssh_target_host(host) 閉環。

Re-Review 評分: 91/100  通過

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-07 11:13:49 +08:00
OG T
0dec007673 docs(logbook): 記錄 Sprint 3 P0 critical security fixes 完成
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 11m37s
2026-04-07 11:10:48 +08:00
OG T
f8d4772abf fix(api): Sprint 3 P0-1/P0-2/P0-3/P0-4 Critical Security Fixes
P0-1: Complete shell metacharacter regex detection
  - Enhanced _SHELL_METACHAR_RE to detect: >, <, \n, ${}, $()
  - Prevents all shell injection vectors (redirects, variable expansion, newlines)
  - Added 5 new validation tests

P0-2: Add shlex.quote() protection for ansible playbook path
  - Wraps playbook_path in shlex.quote() before SSH command construction
  - Prevents shell injection if path contains special characters
  - Applied in _execute_ansible() method

P0-3: Add SSH target host whitelist validation
  - Introduces validate_ssh_target_host() function
  - Only allows SSH to: 192.168.0.110, 192.168.0.188
  - Prevents unauthorized SSH target exploitation
  - Added 5 new whitelist validation tests

P0-4: Convert HostRepairAgent to singleton pattern
  - Implements __new__() singleton with shared _in_process_locks dict
  - Ensures in-process locks persist across multiple auto_repair_service calls
  - Previously created new instance per call, making locks ineffective
  - Added singleton persistence test

Test Results: 45/45 passing (34 existing + 11 new P0 tests)
All security validations verified via comprehensive unit test coverage.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-07 11:09:45 +08:00
OG T
af07c23675 fix(k8s): known_hosts 改掛 /etc/repair-known-hosts 獨立目錄,修 mount 衝突
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m11s
E2E Health Check / e2e-health (push) Successful in 34s
/etc/repair-ssh 已被 repair-ssh-key 佔用,subPath 檔案掛載衝突
改為獨立目錄 /etc/repair-known-hosts,路徑同步更新 KNOWN_HOSTS_PATH

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:06:28 +08:00
OG T
d56aae135d fix(k8s): repair-known-hosts secret optional:true — Pod 不阻塞等待 secret 建立
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 8m35s
CD 首次跑時才建立 secret,optional 讓 Pod 先起來
等 CD 建立 secret 後自動掛載

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:48:45 +08:00
OG T
93bcfb4ce8 docs: 更新 LOGBOOK — Sprint 3 SSH_COMMAND 指揮權鏈完成 2026-04-06 14:48:11 +08:00
OG T
ee187dcb79 ci(cd): CD 自動建立 awoooi-repair-known-hosts Secret (Sprint 3 T2 閉環)
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
每次部署時 ssh-keyscan .110/.188 並 kubectl apply secret
替換 StrictHostKeyChecking=no — Security Fix A1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:45:20 +08:00
OG T
1644fe6474 feat(api): auto_repair_service 整合 repair_by_uri (Sprint 3 T6)
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:39:03 +08:00
OG T
a4e11bfa92 feat(api): AuditLog + Langfuse Trace for SSH_COMMAND (Sprint 3 T5)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:38:59 +08:00
OG T
02510d3d93 feat: /api/v1/auto-repair/history endpoint + neural-command 接真實 API (Sprint 3)
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 8m50s
- 新增 RepairHistoryItem/RepairHistoryResponse Pydantic models
- GET /api/v1/auto-repair/history?limit=N 從 incidents working memory 推導修復歷史
- 前端 fetchData() 同時拉 history + approvals/pending,移除硬編碼 pendingApprovals=0
- try/except 包覆確保任何錯誤都回傳空列表不中斷前端

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:28:55 +08:00
OG T
4561f141bb feat(api): Redis 冪等鎖防止重複修復 (Sprint 3 T4)
雙層鎖設計: in-process asyncio.Lock (必定生效) + Redis 分散式鎖 (跨 Pod best-effort)
同一 URI 的第二次修復呼叫立即返回 "already running" 錯誤

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:26:53 +08:00
OG T
1a654aa37d feat(api): HostRepairAgent 三條執行路徑 + known_hosts + Ansible 白名單 (Sprint 3 T3)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:22:54 +08:00
OG T
d4cb9a4ac5 ops(k8s): known_hosts Secret + Ansible 白名單 ConfigMap (Sprint 3 T2)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:20:14 +08:00
OG T
5e8b2a6894 feat(api): URI scheme 解析器 + Shell Injection 防護 (Sprint 3 T1)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:18:21 +08:00
OG T
9197994d51 feat(neural-command): 加入 Sprint 3 指揮鏈可視化 + T1-T7 任務進度監控
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 11m15s
- SSH Gateway → URI解析器 → Shell防注入 → Redis冪等鎖 → Ansible Playbook DB 節點流程圖
- T1-T7 任務卡片 (T1/T2 標記完成,T3-T7 待執行)
- 4 指標面板:實作速度/安全等級/可觀測性/架構健康度

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:13:58 +08:00
OG T
1a8021bfaa docs(plans): Sprint 3 SSH_COMMAND 指揮權鏈實作計畫 (7 tasks) 2026-04-06 14:08:28 +08:00
OG T
0b1ceb8618 feat(web): 新增神經指揮中心頁面 /neural-command
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m22s
Sprint 3 SSH_COMMAND 指揮權鏈 UI — 完整前端實作:

- Pre-Flight 審查面板: 8/8 安全檢查 (A/B/C 三類) + 通過狀態 + 功能開關
- 即時指揮中心: OpenClaw 🦞 + NemoTron  狀態 + 神經傳導鏈路動畫 + 執行串流
- 統計 & 歷史: 5 KPI + URI scheme 分佈 + Playbook 成效排名 + 時間軸
- 核鑰授權面板: 兩位指揮官診斷 + 執行路徑詳情 + NuclearKeyButton 長按確認

技術:
- 路由: /neural-command (獨立新頁面,非取代 /auto-repair)
- sidebar: BrainCircuit icon,緊接 auto-repair 下方
- i18n: 完整 zh-TW + en 支援 (neuralCommand namespace)
- TypeScript: 型別定義獨立至 components/neural-command/types.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:01:31 +08:00
OG T
0da827beef perf(web): Dockerfile 加入 --mount=type=cache 持久化 Next.js build cache
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 13m37s
CACHE_BUST 仍強制讓 source 層失效(確保代碼變更進入 bundle),
但 .next/cache 透過 BuildKit cache mount 跨 build 持久化到 runner host。
Next.js 增量編譯只重建有變更的頁面,預計節省 3-4 分鐘。

# 2026-04-06 ogt: Web build 從 5 min 降至 ~1-2 min(第二次起)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:45:43 +08:00
OG T
a4ae74f767 fix(cd): 修正 Playwright 版本偵測路徑 ../package.json → ./package.json
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
在 apps/web 目錄執行,../package.json 不存在故每次都回傳 unknown
導致每次部署都重下載 110MB Chromium。
改用 ./package.json 正確讀取 apps/web 的 @playwright/test 版本。

# 2026-04-06 ogt: 節省 CD 約 2 分鐘

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:44:45 +08:00
OG T
cd37befbe6 fix(models): 全面替換 datetime.UTC → timezone.utc 相容 Python 3.10
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Type Sync Check / check-type-sync (push) Successful in 59s
terminal.py, incident.py, utils/timezone.py 同樣問題。
CI runner Python 3.10 無 UTC 常數,導致所有模型靜默 import 失敗。

# 2026-04-06 ogt: 完整修復,不再有漏網之魚

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:40:27 +08:00
OG T
59c3dfb910 fix(models): approval.py 改用 timezone.utc 相容 Python 3.10
Some checks failed
CD Pipeline / build-and-deploy (push) Successful in 12m12s
Type Sync Check / check-type-sync (push) Failing after 52s
CI runner 用 Python 3.10,datetime.UTC 是 3.11 才加入。
改用 datetime.timezone.utc 全版本相容,修復 CI type-sync 全量失敗。

# 2026-04-06 ogt: root cause — CI Python 3.10 無法 import UTC

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:19:23 +08:00
OG T
b416ab6577 ci(debug): type-sync-check 加入 diff 輸出以診斷 CI 失敗原因
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:17:36 +08:00
OG T
8235f91bc6 fix(scripts): generate-schemas 同時加入 apps/api 和 apps/api/src 到 sys.path
Some checks failed
Type Sync Check / check-type-sync (push) Failing after 56s
問題: CI type-sync-check 持續失敗
原因: 只加 apps/api/src 不夠,模型檔內部用 from src.utils.X import Y
     需要 apps/api 在 path 才能解析 src 套件
結果: 51 個型別全部正確生成

# 2026-04-06 ogt: fix CI type-sync blocking deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:00:18 +08:00
OG T
f6332b4b2f fix(telegram): 修正 approval_id UUID 轉換錯誤 — 支援 INC-xxx 格式
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m24s
_execute_approval_action 用 UUID(approval_id) 但 approval_id 是 INC-xxx,
導致 'badly formed hexadecimal UUID string' 錯誤,簽核無法執行。

修正: 先嘗試 UUID 轉換,失敗則用 incident_id 查出對應的 pending approval UUID。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:53:48 +08:00
OG T
71715506c3 chore(types): 重新產生 TypeScript 型別 — Phase 26 ApprovalRequest + namespace 修正
Some checks failed
Type Sync Check / check-type-sync (push) Failing after 51s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:50:43 +08:00
OG T
8d496e84e2 fix(test): 更新 action_parsing 測試 — 無 -n 參數預設 namespace 改為 awoooi-prod
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
action_planner.py default_namespace 已是 awoooi-prod,測試預期值同步更新。
明確指定 -n default 的 kubectl 命令保持不變。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:49:24 +08:00
OG T
b133631b2d feat(scripts): Phase 26 補寫腳本 — 從 approval_records 反向建立 KM
225 筆歷史告警處理記錄全部補寫到 knowledge_entries (INCIDENT_CASE)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:47:47 +08:00
OG T
658337ec18 fix(phase26): 打通 Incident→DB→KM 完整鏈路 + namespace 修正
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 1m29s
Type Sync Check / check-type-sync (push) Failing after 52s
問題根因:
1. create_incident_for_approval 只存 Redis,不存 PostgreSQL
   → TTL 7天後消失,Playbook 萃取永遠找不到 Incident
2. ApprovalRecord 無 incident_id 欄位
   → _trigger_playbook_extraction 靠 regex 掃中文文字找 INC-,永遠失敗
3. operation_parser namespace fallback 是 "default"
   → 所有 deployment 在 awoooi-prod,203 次執行全失敗

修復:
- Incident 同時寫入 Redis + PostgreSQL (save_to_episodic_memory)
- ApprovalRecord 加入 incident_id 欄位 (model + ORM + migration)
- alertmanager_webhook 建立 Approval 後回寫 incident_id
- _trigger_playbook_extraction 直接用 approval.incident_id
- operation_parser DEFAULT_NAMESPACE = "awoooi-prod"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:46:05 +08:00
OG T
286a96d1aa fix(knowledge): entrystatus enum 大小寫修正 'archived' → 'ARCHIVED'
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m47s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:25:44 +08:00
OG T
b9ee58f752 fix(cd): 移除 parse_mode=HTML 避免 commit message 特殊字元造成 400 (non-fatal)
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 13m15s
E2E Health Check / e2e-health (push) Successful in 36s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 22:32:02 +08:00
OG T
b58178d46a chore(types): 重新產生 TypeScript 型別 — is_high_quality 冷啟動閾值調整
Some checks failed
Type Sync Check / check-type-sync (push) Failing after 52s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 22:16:03 +08:00
OG T
09d965dab5 fix(telegram): 修正 editMessageText 400 錯誤 — 先移除按鈕再更新文字
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 12m46s
原因: original_text 來自 message.text (純文字),含 <>&等字符,
     用 parse_mode=HTML 發送時 Telegram 返回 400。

修正:
1. 先呼叫 editMessageReplyMarkup 移除按鈕 (確保按鈕一定消失)
2. 再 html.escape(original_text) 後嘗試更新文字
3. 文字更新失敗不影響整體流程 (按鈕已移除為首要目標)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 22:13:54 +08:00
OG T
5499169996 feat(auto-repair): 打通自動修復閉環 (ADR-058)
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Type Sync Check / check-type-sync (push) Failing after 53s
問題: 告警鏈路從未呼叫 auto_repair_service,機制完全死路
修正:
1. webhooks.py: alertmanager_webhook 建立 Incident 後觸發 _try_auto_repair_background
2. playbook.py: is_high_quality 門檻降低 (冷啟動期)
   - success_count: 10 → 3
   - success_rate: 95% → 80%
3. tests: test_evaluate_not_high_quality 更新為新門檻

流程: Alertmanager → API → Incident → evaluate → P2以下+高品質Playbook → 自動執行 → Telegram通知

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 22:08:08 +08:00
OG T
9629367bc2 fix(webhook): Gitea 簽章格式修正 — 純 hex,無 sha256= 前綴
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 13m12s
Gitea X-Gitea-Signature 送出純 hex(與 GitHub X-Hub-Signature-256 不同)
- router: 兩種格式皆接受(向後相容)
- tests: generate_signature 改為純 hex(符合 Gitea 實際行為)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 15:40:40 +08:00
OG T
a83253da0e fix(gitea-webhook): X-Gitea-Signature 為純 hex,無 sha256= 前綴
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 12m39s
Gitea 送出的簽章 header 是純 hex digest,不含 "sha256=" 前綴。
修正驗證邏輯兼容兩種格式(sha256= 前綴自動去除,否則直接用)。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 15:15:36 +08:00
OG T
dfe41759cc fix(cd): GITEA_WEBHOOK_SECRET secret 名稱改 AWOOOI_GITEA_WEBHOOK_SECRET (保留字問題)
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m25s
Gitea 拒絕以 GITEA_ 開頭的 Secret 名稱(保留字),
改用 AWOOOI_GITEA_WEBHOOK_SECRET,環境變數名稱不變。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:57:23 +08:00
OG T
e51a68d309 docs(logbook): 記錄 Telegram/CD 顯示修復 + ADR-059 全部完成 2026-04-05 14:49:10 +08:00
OG T
8220027298 fix(telegram+cd): 兩個顯示 bug 修正
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
1. Nemotron args 顯示 Python dict 字串問題
   - restart_deployment: {'deployment_name': 'awoo'} → restart_deployment: deployment_name=awoooi-api
   - 改用 key=value 格式化,不再使用 str(dict)[:25]

2. CD 通知 ${MINUTES}/${SECONDS} 等變數未展開
   - TG_MSG 從 env: 移到 run: shell 中組裝
   - env: 中的 shell 變數在 bash 執行前是靜態字串,無法展開

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:47:52 +08:00
OG T
35d37111f0 docs(logbook): ADR-059 全計劃執行完畢 (Task 1-9)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:47:05 +08:00
OG T
59e7879dfb feat(webhook): Task 5 — tests GitHub→Gitea (ADR-059)
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
- test_gitea_webhook.py: 10 tests, X-Gitea-* headers
- conftest.py: GITEA_WEBHOOK_SECRET / GITEA_ALLOWED_REPOS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:45:32 +08:00
OG T
d9af8e1c7a docs(logbook): ADR-059 Gitea Webhook 遷移完成記錄
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:45:02 +08:00
OG T
23364423fa feat(webhook): ADR-059 GitHub → Gitea Webhook 遷移完成
- gitea_webhook.py: Header 全部改 X-Gitea-*,移除 workflow_run handler
- gitea_webhook_service.py: _fetch_pr_diff 改直接 httpx,不依賴 github_api_service
- 清除兩個檔案的所有殘留 github_ log key,review_id prefix 改 gitea-
- test_gitea_webhook.py: 10/10 通過,docstring 修正
- 03-secrets.yaml: 新增 GITEA_WEBHOOK_SECRET 佔位
- cd.yaml: 新增 GITEA_WEBHOOK_SECRET 注入步驟
- ADR-059: 建立架構決策文件

待統帥操作: Gitea Actions secret + Gitea UI Webhook 設定

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:44:32 +08:00
OG T
b2c0148f2b feat(webhook): Task 3 — gitea_webhook.py router (ADR-059)
- 新增 Gitea Webhook Router: X-Gitea-Event/Signature/Delivery
- 支援 pull_request / push / ping,移除 workflow_run
- review_id prefix 改為 gt-pr-* / gt-push-*

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:41:12 +08:00
OG T
6777532534 feat(webhook): Task 1+2 — config + service GitHub→Gitea 遷移 (ADR-059)
- config.py: GITHUB_WEBHOOK_SECRET/ALLOWED_REPOS → GITEA_*
- 新增 gitea_webhook_service.py: PR/Push review only, 移除 CI diagnosis
- 移除 CIFailureDiagnosis, diagnose_ci_failure, _call_openclaw_ci_diagnosis

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:33:58 +08:00
OG T
84f1f9f021 refactor(config): GITHUB_WEBHOOK_SECRET → GITEA_WEBHOOK_SECRET (ADR-059) 2026-04-05 14:25:47 +08:00
OG T
be60ec1507 docs(plan): ADR-059 Gitea Webhook 遷移實作計畫 (9 Tasks)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:22:29 +08:00
OG T
22ee9b2fe3 fix(telegram): answerCallbackQuery result=true 導致 bool is not iterable
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 13m3s
Telegram answerCallbackQuery 成功時返回 {"ok": true, "result": true},
_send_request 中 "message_id" in result["result"] 對 bool 做 in 操作
報 "argument of type 'bool' is not iterable"。

修正:加 isinstance(result_val, dict) 防禦後再做 in 檢查。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:20:54 +08:00
OG T
5cd67d372f docs(spec): ADR-059 Gitea Webhook 遷移設計規格
從 GitHub Webhook (Phase 13.1) 遷移至 Gitea Webhook
最少改動策略:Header 常數替換,業務邏輯層不動
廢棄 workflow_run CI 診斷(CD pipeline 已有 TG 通知覆蓋)
整合首席架構師護欄:防禦性 payload 解析 + Content-Type 設定

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:17:13 +08:00
OG T
6937238174 docs(logbook): 記錄 Telegram 按鈕修復 + SRE 群組格式升級 2026-04-05 14:17:11 +08:00
OG T
4b4007db6c feat(telegram): SRE 群組告警格式升級為完整 v7.0
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
_send_approval_card_to_group 改用與個人 chat 相同的 TelegramMessage.format()
格式,包含 SignOz metrics、AI provider/model、Nemotron 協作、異常頻率統計等全部欄位。

統帥指示:群組收到的告警訊息要與個人 chat 格式完全一致。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:11:59 +08:00