# ops/monitoring/ollama_health_rules.yaml
# AWOOOI Ollama 容災健康告警規則
# 2026-04-26 P2.3 by Claude Sonnet 4.6 (tool-expert) — Ollama 容災監控告警規則
# 2026-05-03 ogt: ADR-110 GCP 三層容災，更新健康規則 action 說明（GCP-A/B + Local）
# 部署目標: 與 alerts-unified.yml 一起部署到 192.168.0.110:/home/wooo/monitoring/alerts.yml
# 部署方式: 手動合併至 alerts-unified.yml，或 scripts/ops/deploy-alerts.sh 支援多檔時直接引用
#
# 標籤規範 (對齊 alerts-unified.yml):
#   layer: ai-provider
#   team: ai
#   auto_repair: "true" | "false"
#
# ⚠️ Backlog 指標（尚未在 API 暴露，需 Part 3 補完後才能啟用）：
#   - OllamaSlowInference: ollama_inference_duration_seconds_bucket — BACKLOG
#   - GeminiQuotaApproaching: gemini_daily_call_count / gemini_daily_quota — 部分實作
#     (Redis key 存在，但 Prometheus Gauge 需 Part 3 手動刷新)
#   - AutoRepairVerificationFailureHigh: post_execution_verification_* — BACKLOG
#   以上規則已寫入但標記 # [BACKLOG]，上線前需先確認 metric 已暴露

groups:

  # ===========================================================================
  # Ollama 容災健康 (ollama_health)
  # ===========================================================================
  - name: ollama_health
    interval: 30s
    rules:

      # -----------------------------------------------------------------------
      # 🔴 [ACTIVE] Ollama 主機離線
      # metric: up{job=~"ollama_gcp_a|ollama_gcp_b|ollama_local|ollama_111"}
      # 前置條件: Prometheus scrape job 命名對齊 ADR-110 provider pool
      #   (設定位於 ops/monitoring/generated/prometheus-scrape-generated.yaml)
      # -----------------------------------------------------------------------
      - alert: OllamaInstanceDown
        expr: up{job=~"ollama_gcp_a|ollama_gcp_b|ollama_local|ollama_111"} == 0
        for: 2m
        labels:
          severity: critical
          layer: ai-provider
          team: ai
          auto_repair: "false"
          alert_category: "ollama_failover"
        annotations:
          summary: "Ollama {{ $labels.job }} 離線 ({{ $labels.instance }})"
          description: "Prometheus 探測 Ollama {{ $labels.job }} 失敗超過 2 分鐘。預期容災應已觸發，路由已切 Gemini。"
          runbook: "docs/runbooks/RUNBOOK-OLLAMA-FAILOVER.md#ollama-instance-down"
          action: "curl http://34.143.170.20:11434/api/tags（GCP-A）或 curl http://34.21.145.224:11434/api/tags（GCP-B）或 ssh wooo@192.168.0.111 'systemctl status ollama'（Local 後備）"

      # -----------------------------------------------------------------------
      # 🟡 [ACTIVE] Failover 觸發頻率過高
      # metric: ollama_failover_triggered_total{from_provider,to_provider}
      # 由 apps/api/src/core/metrics.py OLLAMA_FAILOVER_TRIGGERED_TOTAL 暴露
      # -----------------------------------------------------------------------
      - alert: OllamaFailoverFrequent
        expr: rate(ollama_failover_triggered_total[1h]) > 5
        for: 10m
        labels:
          severity: warning
          layer: ai-provider
          team: ai
          auto_repair: "false"
          alert_category: "ollama_failover"
        annotations:
          summary: "Ollama 容災觸發頻率 > 5/h，主機可能不穩定"
          description: "過去 1 小時 Ollama failover 超過 5 次。建議檢查 111 主機穩定性。"
          runbook: "docs/runbooks/RUNBOOK-OLLAMA-FAILOVER.md#failover-frequent"
          action: "curl http://34.143.170.20:11434/api/tags 或 ssh wooo@192.168.0.111 'nvidia-smi && journalctl -u ollama -n 50'（GCP-A 掛才用 111）"

      # -----------------------------------------------------------------------
      # 🟡 [ACTIVE] Auto Recovery 停滯（111 已恢復但仍走 Gemini）
      # metric: ollama_health_status{host} (Gauge, 0=offline, 1=healthy)
      #         ollama_current_primary_is_ollama (Gauge, 1=primary是ollama)
      # 兩個 metric 均由 Part 3 補入
      # -----------------------------------------------------------------------
      - alert: OllamaRecoveryStuck
        expr: |
          ollama_health_status{host="111"} == 1
          and
          ollama_current_primary_is_ollama == 0
        for: 5m
        labels:
          severity: critical
          layer: systemd-188
          team: ai
          auto_repair: "false"
          alert_category: "ollama_failover"
        annotations:
          summary: "111 已 HEALTHY 但路由仍走 Gemini，auto recovery 可能停滯"
          description: "OllamaHealthMonitor 回報 111=HEALTHY 已超過 5 分鐘，但 primary 仍非 ollama。請確認 OllamaAutoRecoveryService 是否正常運行。"
          runbook: "docs/runbooks/RUNBOOK-OLLAMA-FAILOVER.md#recovery-stuck"
          action: "kubectl logs -n awoooi-prod deploy/api | grep ollama_auto_recovery | tail -20"

      # -----------------------------------------------------------------------
      # 🟡 [BACKLOG] P99 推理延遲過高
      # metric: ollama_inference_duration_seconds_bucket — 尚未暴露，需 Part 3 補入
      # -----------------------------------------------------------------------
      # [BACKLOG] 等 ollama_inference_duration_seconds_bucket 暴露後啟用
      # - alert: OllamaSlowInference
      #   expr: |
      #     histogram_quantile(0.99,
      #       rate(ollama_inference_duration_seconds_bucket[5m])
      #     ) > 30
      #   for: 5m
      #   labels:
      #     severity: warning
      #     team: ai
      #   annotations:
      #     summary: "Ollama P99 推理延遲 > 30s"
      #     action: "curl http://34.143.170.20:11434/api/tags 或 ssh wooo@192.168.0.111 'nvidia-smi'（GCP-A 掛才用 111）"

      # -----------------------------------------------------------------------
      # 🟡 [PARTIAL] Gemini 配額即將耗盡
      # metric: gemini_daily_call_count (Gauge)
      #         gemini_daily_quota (Gauge)
      # Redis key "ollama:gemini_daily_count:{date}" 已存在
      # Gauge 需由 Part 3 補入（從 Redis 讀出並設值）
      # -----------------------------------------------------------------------
      - alert: GeminiQuotaApproaching
        expr: gemini_daily_call_count / gemini_daily_quota > 0.8
        for: 5m
        labels:
          severity: warning
          layer: systemd-188
          team: ai
          auto_repair: "false"
          alert_category: "ollama_failover"
        annotations:
          summary: "Gemini 每日配額已用 >80%，即將觸發 failover"
          description: "每日 Gemini call 已超過配額 80%。當日剩餘配額不足時，路由將自動切至 188 CPU-only 備援。"
          runbook: "docs/runbooks/RUNBOOK-OLLAMA-FAILOVER.md#gemini-quota"
          action: "確認 GEMINI_DAILY_QUOTA 設定值，考慮升級配額或提前切 Nemotron"

      # -----------------------------------------------------------------------
      # 🟡 [BACKLOG] Auto Repair Verifier 失敗率高（飛輪健康）
      # metric: post_execution_verification_failed_total — 尚未暴露
      #         post_execution_verification_total       — 尚未暴露
      # -----------------------------------------------------------------------
      # [BACKLOG] 等 post_execution_verification_* 暴露後啟用
      # - alert: AutoRepairVerificationFailureHigh
      #   expr: |
      #     sum(rate(post_execution_verification_failed_total[15m])) /
      #     sum(rate(post_execution_verification_total[15m])) > 0.3
      #   for: 10m
      #   labels:
      #     severity: warning
      #     team: ai
      #   annotations:
      #     summary: "Auto Repair Verifier 失敗率 >30%（飛輪可能腐爛）"
