> ## Documentation Index
> Fetch the complete documentation index at: https://docs.traffical.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy health

> Diagnostics for running policies: exposures flowing, sample ratio, per-allocation floors, freshness, guardrails, and optimizer eligibility.

The **Policy health** view tracks the runtime behaviour of every running policy
and flags the failure modes that quietly invalidate experiments — missing
exposures, sample-ratio mismatches, freshness gaps, breached guardrails,
and stuck optimizers.

It's the runtime sibling of the
[launch-readiness checklist](/dashboard/layers-and-policies#overview-tab)
that gates draft policies before they start.

<Frame caption="Policy health hero">
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/traffical/images/placeholders/policy-health-hero.png" alt="Policy health hero placeholder" />
</Frame>

## Where you see it

Open any policy detail page:

* The **Overview** tab shows a compact health hero that auto-collapses when
  everything is green. Click any pill to see per-check detail. The tab's
  **Live allocation** digest also shows traffic share and exposures per
  variant, so a variant that stopped receiving exposures stands out at a
  glance.
* The **Diagnostics** tab (between **Measurement** and **Decisions**) shows
  the full assignments time-series, optional SRM history chart, and the
  transition log. Its tab label carries a `(!)` while any check is warning
  or failing.

The hero is hidden in `draft` state — the readiness checklist covers that
phase.

## The six checks (v1)

| Check                     | Sources                                                                      | Pass / Warn / Fail                                                                                                        |
| ------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Exposures flowing**     | Hourly per-allocation counts from the pipeline rollup                        | Pass: any in last 15 min. Warn: none in 1 h but some in 24 h. Fail: none in 24 h.                                         |
| **Sample ratio mismatch** | Chi-squared on observed vs expected ratios                                   | Pass: p ≥ 0.01. Warn: 0.001 ≤ p \< 0.01. Fail: p \< 0.001 **and** > 0.1 pp absolute deviation.                            |
| **Per-allocation floor**  | Lifetime totals per allocation                                               | Pass: all ≥ floor. Warn: some below floor. Fail: any at zero while others are healthy.                                    |
| **Data freshness**        | Pipeline rollup `computedAt` + watermarks                                    | Pass: \< 30 min. Warn: \< 6 h. Fail: > 24 h.                                                                              |
| **Guardrail breach**      | Latest `MetricSnapshot.allocations[].guardrailStatus`                        | Pass: all passing. Warn: insufficient data. Fail: any failing.                                                            |
| **Optimization eligible** | Last optimization run + `learningState.lastUpdated` (adaptive policies only) | Pass: last run updated / `no_change`. Warn: `insufficient_exposures` / `too_soon`. Fail: errored, or no run in last 24 h. |

### Adaptive SRM semantics

For adaptive policies, the SRM baseline is the **current** optimizer weighting
(the latest `allocationHistory` entry). The check re-baselines on every
rebalance — a rebalance that legitimately changes the split will not trip the
check on its own. The side sheet shows which baseline was used for the
current evaluation.

## Transition events

Every rollup compares the new health JSON against the previous JSON. Any
check whose status changed (including pass → warn) writes a
`PolicyHealthEvent` row.

These power the per-check **Transitions** list in the side sheet and the
timeline at the bottom of the Diagnostics tab. The same transitions feed
[Notifications](/dashboard/notifications) — a check that starts failing or
recovers lands in the **Policy** category, deliverable in-app, by email, or
to a shared Slack channel.

## Endpoints

The dashboard reads three endpoints; the same endpoints are available via
the API:

* `GET /v1/policies/:policyId/health` — derived report (six checks + overall)
* `GET /v1/policies/:policyId/health/timeseries?window=24h|7d|30d|lifetime` —
  per-allocation series + SRM snapshot for the chart
* `GET /v1/policies/:policyId/health/events?since=...&limit=...` — transition
  history

All three return `pending` / empty payloads when the pipeline hasn't run
yet, so the UI never errors during a policy's first few minutes.

## How it's computed

1. The warehouse-native pipeline emits a `PolicyHealthJson` per running
   policy as the last phase of every run (`policy-health-rollup`). The
   rollup runs three queries against `_p_{policyId}_assignments` (hourly
   24 h, daily 30 d, lifetime) and computes chi-squared in process.
2. Traffical persists the report and compares it to the previous run's
   report to detect transitions, recording each status change as a
   `PolicyHealthEvent` in the same step.
3. On request, the stored report and transition history feed a pure
   function that maps the raw data into the six checks + an overall
   rollup. Identical inputs produce identical outputs, so the same report
   always renders the same way.

For more on the underlying data model, see
[Warehouse-native](/concepts/warehouse-native).
