Skip to main content

docs/slo-reference.md

# Parapet SLO Reference

Parapet now has two SLO paths:

1. Legacy `%Parapet.SLO{}` definitions for existing custom slices.
2. Provider-owned Phase 5 slice specs for built-in async and delivery reliability.

The blessed path for built-ins is explicit provider registration plus host-owned generated Prometheus files.

## Phase 5 Provider Registration

Register built-in providers through application config:

```elixir
config :parapet,
  providers: [
    Parapet.SLO.MailglassDelivery,
    Parapet.SLO.ChimewayDelivery,
    Parapet.SLO.RindleAsync
  ]
```

`Parapet.attach(adapters: [...])` only enables telemetry adapters. It does not auto-register SLO providers or silently generate alerts.

## Built-In Provider Modules

- `Parapet.SLO.MailglassDelivery`
  - `mailglass_submit_acceptance`
  - `mailglass_confirmed_delivery`
  - `mailglass_webhook_freshness`
  - `mailglass_suppression_drift`
- `Parapet.SLO.ChimewayDelivery`
  - `chimeway_provider_acceptance`
  - `chimeway_callback_confirmation`
  - `chimeway_callback_freshness`
- `Parapet.SLO.RindleAsync`
  - `rindle_terminal_success`
  - `rindle_queue_freshness`
  - `rindle_callback_freshness`
  - `rindle_long_running_stage`
  - `rindle_funnel_regression`

These providers return bounded `Parapet.SLO.SliceSpec` structs. The generator owns the PromQL shape so built-ins stay low-cardinality and symptom-first.

## Starter Packs

Starter packs are opinionated, one-line SLO bundles for common application shapes. They are provider modules like any other — register them in `config :parapet, providers: [...]` and run `mix parapet.gen.prometheus`. Each slice is pinned to a real emitted Prometheus series, ships a documented default objective in human terms, and is overridable.

- `Parapet.SLO.StarterPack.WebSaaS` — first-SLO pack for Phoenix SaaS teams (three slices):
  - `web_saas_http_availability` — source `parapet_http_request_count`, 99.5% objective, `:ticket` alert class
  - `web_saas_login_journey` — source `parapet_journey_login_count`, 99.9% objective, `:page` alert class
  - `web_saas_oban_job_success` — source `parapet_oban_jobs_total`, 99.0% objective, `:ticket` alert class
- `Parapet.SLO.StarterPack.DeliverySaaS` — extends WebSaaS for delivery-sending teams. Composes the three WebSaaS slices above with the `Parapet.SLO.MailglassDelivery` and `Parapet.SLO.ChimewayDelivery` catalogs. Delivery slices register **only when the corresponding host library is loaded** (guarded by `Code.ensure_loaded?(Mailglass)` / `Code.ensure_loaded?(Chimeway)`), so the pack compiles out cleanly to just the three WebSaaS slices when delivery providers are absent. See the [Provider-as-bundle pattern](docs/slo-authoring-guide.md#provider-as-bundle-pattern) in the SLO authoring guide for how to build your own bundle provider.

All starter-pack slices use the default `min_total_rate: 0.01` denominator guard. See the [SLO authoring guide](docs/slo-authoring-guide.md) for how to read, anchor on, and override these defaults.

## Generated Artifacts

Run:

```bash
mix parapet.gen.prometheus
```

This task reads active providers only and writes:

- `priv/parapet/prometheus/recording_rules.yml`
- `priv/parapet/prometheus/alerts.yml`
- `priv/parapet/prometheus/rules.yml`

`rules.yml` is the compatibility aggregate. The split `recording_rules.yml` and `alerts.yml` files are the preferred host-owned path.

## Legacy Compatibility

`Parapet.SLO.define/2` and legacy `%Parapet.SLO{}` values still work, but they are compatibility surfaces. New async and delivery slices should be implemented as provider modules instead of mutating the `:slos` application env at runtime.

## Runbooks And Severity

Runbooks remain mandatory. Every generated alert carries a runbook URL and a bounded severity:

- `page` for terminal or clearly user-harming symptoms
- `ticket` for sustained but less urgent degradation
- `warning` for early or lower-confidence regressions

Phase 5 also keeps retry noise and freshness failures separate. Queue backlog, callback delay, suppression drift, and terminal discard are different operator symptoms and generate different slices.