# ops/monitoring/grafana/agent_step_latency_rules.yaml
# AWOOOI Agent Step Latency 告警規則
# 2026-04-27 Claude Sonnet 4.6: A3 — Agent step latency observability (config A+B Wave 1)
# 2026-04-27 Claude Sonnet 4.6: F7 — 補完整部署 SOP（critic H 修正）
#
# =============================================================================
# 部署 SOP（F7）— 不可跳步驟，不可實際 apply（SRE 手動執行）
# =============================================================================
#
# 部署模型：Prometheus 在 k8s 110:/home/wooo/monitoring/ 以 docker-compose 運行，
#   prometheus.yml rule_files: ["alerts.yml"] 只載入單一檔案；
#   本 yaml 需手動合併至 alerts-unified.yml → 部署為 alerts.yml。
#
# 步驟 1 — 本機語法驗證（必須 PASSED，否則不合併）
#   promtool check rules ops/monitoring/grafana/agent_step_latency_rules.yaml
#   # 預期輸出包含：Checking ... SUCCESS
#
# 步驟 2 — 合併到 alerts-unified.yml（DBA/SRE 手動）
#   # 將 groups[0]（agent_step_latency）整段 yaml 貼入
#   # ops/monitoring/alerts-unified.yml 的 groups: 清單末尾
#   # 合併後再次驗證整體檔案：
#   promtool check rules ops/monitoring/alerts-unified.yml
#
# 步驟 3 — 部署（透過既有 CD 流程）
#   # 標準路徑（CD 自動）：
#   git push gitea main   # Gitea CI 跑 scripts/ops/deploy-alerts.sh
#   #
#   # 緊急手動路徑（SRE 授權）：
#   scp ops/monitoring/alerts-unified.yml wooo@192.168.0.110:/home/wooo/monitoring/alerts.yml
#   # 再執行 Prometheus reload（步驟 4）
#
# 步驟 4 — Prometheus reload
#   curl -X POST http://192.168.0.110:9090/-/reload
#   # 或（若 Prometheus 在 Docker container 內）：
#   docker exec -it prometheus kill -HUP 1
#
# 步驟 5 — 驗收（三條 alert 全部列出才算完成）
#   curl -s http://192.168.0.110:9090/api/v1/rules \
#     | python3 -m json.tool \
#     | grep '"name"' \
#     | grep -E "AgentStepLatencyHigh|AgentStepTimeoutSpike|DiagnoseFallbackToCloud"
#   # 預期：三行都出現
#
# =============================================================================
#
# 部署目標：與 alerts-unified.yml 一起部署到 192.168.0.110:/home/wooo/monitoring/alerts.yml
# 部署方式：手動合併至 alerts-unified.yml（Prometheus rule_files 只接受單一 alerts.yml）
#
# 依賴 Metrics（均由 A1/A2 提供，需 A1+A2 上線後才能 ACTIVE）：
#   - aiops_agent_step_duration_seconds{agent,outcome}   — Histogram, A1 (apps/api/src/observability/agent_step_metrics.py)
#     agent ∈ {diagnostician, solver, critic}
#     outcome ∈ {success, timeout, error}
#     buckets: [0.5, 1.0, 2.0, 5.0, 10.0, 15.0, 20.0, 30.0, 45.0, 60.0]
#   - aiops_diagnose_fallback_total{from_provider,to_provider} — Counter, A2 (apps/api/src/services/ai_router.py)
#     from_provider ∈ {openclaw_nemo, gemini, claude}
#     to_provider   ∈ {gemini, claude}
#
# 標籤規範（對齊 alerts-unified.yml）：
#   layer: k8s        (API 跑在 k8s awoooi-prod namespace)
#   team: ai
#   auto_repair: "false"  (NIM 延遲需人工判斷，不啟動 auto_repair)
#
# 背景：INC-20260425-8D17BB / INC-20260425-3B6C39
#   NIM (192.168.0.188:8088) 實測延遲 2-27s，尾巴 latency 命中 PHASE2_STEP_TIMEOUT_SEC=20s
#   → confidence 降至 20%（degraded），diagnostician/solver/critic 全部失效
#   → fallback 到 Gemini，消耗每日配額
#   本規則組提供全路徑可觀測性：latency high → timeout spike → fallback
#
# ⚠️ 啟用前必須確認：
#   [A1] aiops_agent_step_duration_seconds 已暴露（A1 merge 且 Pod restart 後）
#   [A2] aiops_diagnose_fallback_total 已暴露（A2 merge 且 Pod restart 後）
#   驗證方式：curl http://192.168.0.188:8088/metrics | grep aiops_agent_step
# =============================================================================

groups:

  # ===========================================================================
  # Agent Step Latency (agent_step_latency)
  # 監控三段 Phase 2 Agent（diagnostician/solver/critic）呼叫 LLM 的延遲與失敗
  # ===========================================================================
  - name: agent_step_latency
    interval: 60s
    rules:

      # -------------------------------------------------------------------------
      # [ACTIVE — 需 A1 上線]
      # AgentStepLatencyHigh — p75 延遲持續高水位
      #
      # 觸發條件：任意一個 agent 的 p75 step latency 超過 25s 且持續 10 分鐘
      # 意義：NIM 推理尾巴 latency 偏高，有命中 timeout 的風險
      # 嚴重度：warning（尚未 timeout，但趨勢不好，SRE 應預先介入）
      #
      # PromQL 設計說明：
      #   - rate([5m]) 計算 5 分鐘滑動視窗的 bucket 增量，消除計數器重置問題
      #   - histogram_quantile(0.75, ...) 計算當前視窗的 75th 百分位
      #   - sum by (agent, le) 保留 agent 維度，使每個 agent 獨立觸發
      #   - > 25 對齊 INC-20260425 實測尾巴 latency（最高 27s），低於最寬 timeout 30s
      #   - for: 10m 避免短暫尖刺誤報（10 分鐘連續高水位才通知）
      # -------------------------------------------------------------------------
      - alert: AgentStepLatencyHigh
        expr: |
          histogram_quantile(
            0.75,
            sum by (agent, le) (
              rate(aiops_agent_step_duration_seconds_bucket[5m])
            )
          ) > 25
        for: 10m
        labels:
          severity: warning
          layer: k8s
          team: ai
          auto_repair: "false"
          alert_category: "agent_step_latency"
        annotations:
          summary: "Agent {{ $labels.agent }} p75 step latency > 25s（持續 10m）"
          description: |
            Phase 2 agent {{ $labels.agent }} 過去 5 分鐘 LLM call 的 p75 延遲為
            {{ $value | humanizeDuration }}，超過 25s 門檻持續 10 分鐘。
            NIM 實測尾巴可達 27s；若持續惡化將命中 timeout 並觸發 Gemini fallback。
            建議確認 NIM 健康度（192.168.0.188:8088）及 GPU 負載。
          runbook_url: "docs/runbooks/RUNBOOK-AGENT-STEP-LATENCY.md#agentsteplatencyhigh"

      # -------------------------------------------------------------------------
      # [ACTIVE — 需 A1 上線]
      # AgentStepTimeoutSpike — timeout 事件頻率爆發
      #
      # 觸發條件：任意 agent 每分鐘 timeout 超過 3 次，持續 5 分鐘
      # 意義：Agent 已進入 degraded 狀態，confidence 降至 20%，飛輪失能
      # 嚴重度：critical（已在降級，需立即處理）
      #
      # PromQL 設計說明：
      #   - rate(...)_total 為 Counter metric，需用 rate() 計算速率
      #   - aiops_agent_step_duration_seconds_count{outcome="timeout"} 是
      #     Histogram Counter 的特殊形式，存在於 _count 維度中；
      #     但 prometheus_client Histogram 的 outcome label 在 _bucket/_count/_sum 上均存在
      #   - rate([1m]) * 60 = 每分鐘 timeout 數（rate 本身是 per-second，乘 60 轉換）
      #   - sum by (agent) 使每個 agent 獨立觸發，不混合計算
      #   - > 3 對齊任務規格（每分鐘 > 3 起）
      #   - for: 5m 確認是持續問題，非一過性尖峰
      # -------------------------------------------------------------------------
      - alert: AgentStepTimeoutSpike
        expr: |
          sum by (agent) (
            rate(aiops_agent_step_duration_seconds_count{outcome="timeout"}[1m])
          ) * 60 > 3
        for: 5m
        labels:
          severity: critical
          layer: k8s
          team: ai
          auto_repair: "false"
          alert_category: "agent_step_latency"
        annotations:
          summary: "Agent {{ $labels.agent }} timeout 頻率 > 3/min（持續 5m，飛輪失能）"
          description: |
            Phase 2 agent {{ $labels.agent }} 過去 1 分鐘 timeout 速率為
            {{ $value | humanize }}/min，持續 5 分鐘超過門檻 3/min。
            agent 處於 degraded 狀態（confidence=20%）；診斷、決策、修復全部失效。
            根因通常是 NIM 高負載或網路抖動。需立即查 NIM 及考慮切 provider。
          runbook_url: "docs/runbooks/RUNBOOK-AGENT-STEP-LATENCY.md#agentsteptimeoutspike"

      # -------------------------------------------------------------------------
      # [ACTIVE — 需 A2 上線]
      # DiagnoseFallbackToCloud — NEMO→Gemini fallback 頻率預警
      #
      # 觸發條件：從 openclaw_nemo 到 gemini 的 fallback 每分鐘 > 5 次，持續 5 分鐘
      # 意義：NIM 已無法服務，Gemini 每日配額正在高速消耗，有配額耗盡風險
      # 嚴重度：warning（Gemini 還在服務，但配額燃燒速度需注意）
      #
      # PromQL 設計說明：
      #   - aiops_diagnose_fallback_total 是 Counter，用 rate() + * 60 轉為 /min
      #   - 精確過濾 from_provider="openclaw_nemo", to_provider="gemini"
      #     （最關鍵的 NEMO→Gemini 跳轉，預警 Gemini quota 燒耗）
      #   - 若需監控 Gemini→Claude 第二段 fallback，另建獨立 alert（超出本任務範圍）
      #   - for: 5m 確認持續燃燒，非一過性 NIM 重啟
      # -------------------------------------------------------------------------
      - alert: DiagnoseFallbackToCloud
        expr: |
          rate(
            aiops_diagnose_fallback_total{
              from_provider="openclaw_nemo",
              to_provider="gemini"
            }[1m]
          ) * 60 > 5
        for: 5m
        labels:
          severity: warning
          layer: k8s
          team: ai
          auto_repair: "false"
          alert_category: "agent_step_latency"
        annotations:
          summary: "NEMO→Gemini fallback > 5/min（持續 5m），Gemini quota 正在燃燒"
          description: |
            DIAGNOSE phase 從 openclaw_nemo fallback 到 gemini 的速率為
            {{ $value | humanize }}/min，持續 5 分鐘超過門檻 5/min。
            NIM 主力路由已無法服務；Gemini 每日配額正在高速消耗。
            若 Gemini 配額耗盡，fallback 將轉向 Claude（費用更高）。
            需立即確認 NIM 狀態並決定是否限流或增加 Gemini 配額。
          runbook_url: "docs/runbooks/RUNBOOK-AGENT-STEP-LATENCY.md#diagnosefallbacktocloud"
