# Host + container resource alerts (node-exporter + cAdvisor).
# Routed via alertmanager → discord bridge: severity=critical|warning →
# #briven-alerts, info → #briven-deploys. Severity labels MUST match the
# route matchers in infra/observability/alertmanager/alertmanager.yml.
#
# Thresholds tuned for kvm4: 4 vCPU, 16 GB RAM, 4 GB swap, on an
# oversubscribed Hostinger VPS (CPU steal is a real signal here).
#
# NOTE: Dokploy builds can run as a HOST process (no container cgroup), so
# a runaway build is caught by the host memory/swap alerts below, not by
# the per-container cAdvisor alert. Both layers are intentional.

groups:
  - name: briven-host
    interval: 30s
    rules:
      - alert: HostMemoryCritical
        expr: |
          node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: 'host {{ $labels.instance }} memory critically low'
          description: 'Available memory <5% for 5m ({{ $value | printf "%.1f" }}%). Builds/exec will start failing with OCI "unable to start container process".'

      - alert: HostMemoryHigh
        expr: |
          node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'host {{ $labels.instance }} memory low'
          description: 'Available memory <10% for 10m ({{ $value | printf "%.1f" }}%).'

      - alert: HostSwapHigh
        expr: |
          (1 - node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes) * 100 > 50
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'host {{ $labels.instance }} swapping heavily'
          description: 'Swap usage >50% for 10m ({{ $value | printf "%.0f" }}%). Sustained swap means a process (often a build) is exhausting RAM.'

      - alert: HostDiskHigh
        # rootfs only. With --path.rootfs=/host, node-exporter reports the
        # host root as mountpoint "/". If your build reports "/host", widen
        # the matcher to mountpoint=~"/|/host".
        expr: |
          (1 - node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay|squashfs"}
             / node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay|squashfs"}) * 100 > 85
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'host {{ $labels.instance }} disk >85%'
          description: 'Root filesystem {{ $value | printf "%.0f" }}% full. Run docker builder/image prune.'

      - alert: HostDiskCritical
        expr: |
          (1 - node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay|squashfs"}
             / node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay|squashfs"}) * 100 > 92
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: 'host {{ $labels.instance }} disk >92%'
          description: 'Root filesystem {{ $value | printf "%.0f" }}% full — deploys and Docker will fail imminently.'

      - alert: HostLoadHigh
        # 5-min load above 2x core count. count(idle cpu series) = vCPU count.
        expr: |
          node_load5 > 2 * count by (instance) (node_cpu_seconds_total{mode="idle"})
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'host {{ $labels.instance }} load high'
          description: '5-min load {{ $value | printf "%.1f" }} is >2x vCPU count for 10m.'

      - alert: HostCPUStealHigh
        # Hostinger oversubscription signal — the hypervisor is taking CPU.
        expr: |
          avg by (instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 25
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: 'host {{ $labels.instance }} CPU steal >25%'
          description: 'Hypervisor stealing {{ $value | printf "%.0f" }}% CPU for 15m. VPS is oversold — consider resizing or moving load.'

      - alert: ContainerMemoryHigh
        # Any single container >6 GB RSS. Catches containerized heavy builds
        # and memory-leaking apps. Host-level builds are caught by HostMemory*.
        expr: |
          container_memory_rss{name!=""} > 6e9
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'container {{ $labels.name }} using >6 GB RAM'
          description: '{{ $labels.name }} RSS {{ $value | humanize1024 }}B for 10m on a 16 GB host.'

      - alert: ContainerOOMKilled
        expr: |
          increase(container_oom_events_total{name!=""}[10m]) > 0
        labels:
          severity: warning
        annotations:
          summary: 'container {{ $labels.name }} OOM-killed'
          description: '{{ $labels.name }} hit an OOM event in the last 10m.'

      - alert: ContainerRestarting
        expr: |
          changes(container_start_time_seconds{name!=""}[15m]) > 2
        labels:
          severity: warning
        annotations:
          summary: 'container {{ $labels.name }} restart-looping'
          description: '{{ $labels.name }} restarted >2 times in 15m.'
