# Backtest Alert

```
POST 
/v1/alerts/:alert_id/backtest
```

Has this line ever been crossed, and when? MEASURES ONLY; CHANGES NOTHING.

The question a threshold is chosen against. A user picked `> 2.0` on a column whose 110-day maximum was 0.967; the product accepted it, called it `active`, and answered `not_fired` — **byte-for-byte what a healthy service returns**. An alert that can never fire was indistinguishable from an alert watching something that is fine. This is the number that separates them, and `POST /v1/alerts` returns the same block on creation.

Read `crossings` next to `scope`. **`crossings: 0` is a fact, not an error and not a refusal** — a line nobody has crossed yet is often exactly what you meant to watch for. `note` says it in one sentence, including when the count is a floor because the row cap was hit.

`scope` is not decoration. The condition is opaque SQL, so "available history" means one of two things and the sentence says which: a condition that declares a `window` is re-run with that window WIDENED (never narrowed) and its rows over that span are its crossings; a condition that declares none is run exactly as written, which is all the history it addresses — and if its SQL pins a period with a literal, the count is for that period. A count whose scope is unstated cannot be read.

`status` is always an answer: `ok` ran, `warming_up` means the EC2 SQL worker was cold and the query never ran (retry in a moment — a warm-up has been kicked), `error` carries the same sentence `evaluate_alert` would give for an unmeasurable condition, `skipped` means this alert has no condition and fires on its clock alone.

**What this does not do.** It is not an evaluation. No verdict is recorded, `lastEvaluatedAt` / `lastVerdict` / `lastFiredAt` do not move, nothing is captured, nothing is delivered, no event is published and the hysteresis edge `evaluate_alert` consumes is untouched — so this is safe to call in a loop while you tune a number, which `evaluate_alert` is not.

Read-gated (VIEW on the alert's dashboard, the same gate as `verify` and `GET /v1/alerts/{alert_id}`): it writes nothing and derives strictly what the same caller could get by running the condition's own SQL through `POST /v1/query`.

## Request[​](#request "Lien direct vers request")

## Responses[​](#responses "Lien direct vers Responses")

* 200
* 404
* 422

Successful Response

Not found

Validation Error
