# Chaos drill — what does the client-side picture look like when the backend
# misbehaves? Steady traffic runs its normal flow while a second scenario
# keeps forcing server errors and multi-second stalls (go-httpbin's /status
# and /delay endpoints stand in for a flaky dependency). Scenario-scoped
# thresholds judge the blast radius on the steady traffic only, and the
# abort threshold is the circuit breaker: if errors explode, the run stops
# instead of burning the target.
#
#   docker compose -f examples/harness/docker-compose.yml up -d --build
#   loadr run examples/48-chaos.yaml
#
# Coordinated fault injection (network partitions, node kill, added latency,
# clock skew) is the `loadr chaos` RFC — see
# docs/design/concurrency-consistency-testing.md. The planned schedule shape,
# for when the nemesis lands:
#
#   nemesis:
#     seed: 1234                # reproducible fault schedule
#     faults:
#       - { at: 20s, do: partition, groups: [[node-1], [node-2, node-3]], for: 25s }
#       - { at: 60s, do: kill,      node: primary, for: 15s }
#       - { every: 30s, do: latency, node: any, ms: 200, jitter: 50, for: 10s }
#     heal_at_end: true
name: chaos
description: steady traffic under injected 5xx bursts and stalls, with an abort guard

defaults:
  http:
    base_url: http://127.0.0.1:8080
    timeout: 5s

scenarios:
  # The traffic whose experience we actually care about.
  steady_traffic:
    executor: constant-vus
    vus: 20
    duration: 2m
    flow:
      - request:
          name: browse
          url: /get
          checks:
            - { type: status, equals: 200 }
            - { type: duration, name: within slo, max: 800ms }
      - think_time: { type: uniform, min: 200ms, max: 800ms }

  # The nemesis, hand-rolled: a low steady rate of requests that make the
  # backend hurt — error bursts and slow responses in a 70/30 mix.
  fault_injection:
    executor: constant-arrival-rate
    rate: 5
    time_unit: 1s
    duration: 2m
    pre_allocated_vus: 10
    max_vus: 40
    flow:
      - random:
          strategy: weighted
          choices:
            - weight: 70
              name: error burst
              steps:
                - request: { name: inject 500, url: /status/500 }
            - weight: 30
              name: stall
              steps:
                - request: { name: inject stall, url: /delay/3 }

thresholds:
  # Judge only the steady traffic — the injected faults are SUPPOSED to fail.
  "http_req_failed{scenario:steady_traffic}":
    - { threshold: "rate<0.05", abort_on_fail: true, delay_abort_eval: 20s }
  "http_req_duration{scenario:steady_traffic}": [ "p(95)<800" ]
  "checks{scenario:steady_traffic}": [ "rate>0.95" ]
