> Section: [8. Observing it](https://jaque.sh/docs/ui/dashboard.md)
> Next: observability/archive
> Index: https://jaque.sh/llms.txt


An SLO turns the ad hoc availability view into a named, standing
declaration: a selector, a target percent, and how the report should
treat business hours and scheduled downtime. It has no window of its
own: the range comes from the request each time a report is read, not
from anything stored in the SLO's declaration.

## 1. What an SLO is here

An `slo` block is a named entry under `slos`:

```cue
slos: {
	web_tier: {
		selector:          "team=web"
		target:             99.9
		period:             "office"
		exclude_downtimes:  true
		down_statuses:      ["CRITICAL"]
	}
}
```

- `selector` is the same label-selector grammar a view or a downtime
  uses; it names the objects the SLO measures by query, so an SLO can
  be declared before the hosts it will match exist.
- `target` is the uptime percent the error budget is measured against.
- `period` names a declared timeperiod; while it is set, only the
  period's open time counts toward the report at all, and time outside
  it is neither up, down nor undetermined. Leaving it out measures the
  whole requested range.
- `exclude_downtimes` defaults to true and subtracts the part of down
  time that a scheduled, non-cancelled downtime window overlaps.
- `down_statuses` lists which HARD statuses count as down; leaving it
  out uses every status the state model already treats as a problem.

An `slo` block requires `ui.availability` to be configured: an SLO with
no datasource to measure against is refused at load, before it can ever
answer a request. `ui.availability`'s own datasource now has to
share its host and database with a sink whose input is events; a config
that declares `ui.availability` without such a sink is refused at load
too, with a message naming the host and database it expected to find a
sink writing to.

## 2. How the numbers are computed

Within the SLO's open time, every HARD status accrues its seconds, with
one exception: time the engine recorded an object as unreachable always
counts under its own bucket and wins over whatever HARD status
overlaps it. Down time is the sum of the down set plus unreachable
time. Determined time is every status except PENDING; undetermined
time is what is left of the open time once determined time is
subtracted. Uptime is a percent of determined time, with the excluded
downtime seconds removed from down time first:

```
uptime_pct = 100 * (1 - (down_seconds - downtime_seconds) / determined_seconds)
```

An object with no determined time at all has no uptime percent to
show. The budget is the down time the target still allows, and
consumption is how much of it has actually been used:

```
budget_seconds   = determined_seconds * (1 - target / 100)
consumed_seconds = down_seconds - downtime_seconds
```

A member that matched the selector but has no HARD row at or before the
range end appears in the report with `no_data` set and every count at
zero, so a member with no history is visible instead of missing. Every
report also carries the
earliest timestamp its datasource holds, so a range that starts before
that point shows a data boundary rather than a real 100% or a real gap.

## 3. Reading the report

The dashboard's availability view lists every declared SLO above the ad
hoc object table: name, attained percent against target, a budget bar
showing consumed against allowed, and the member count. Selecting one
loads its per-object table and timeline into the same view the ad hoc
report uses, with the period and the downtime policy shown as fixed
text rather than the checkbox, since both are the SLO's own declaration
rather than something a reader picks per request.

Two RPCs back this: `ListSLOs` returns every declared SLO with its
current member count, the way `ListViews` reports on a view; `QuerySLOReport`
takes an SLO name and a range and returns its declaration, one row per
member with that member's budget alongside its availability, and the
aggregate uptime and budget across the whole SLO.

## 4. What it does not do

Report export, scheduling and mail are not part of this: the RPC is the
export, and a caller that wants a recurring report reads it on its own
schedule. Alerting on budget consumption and multi-window burn rates are
not implemented. An SLO has no rolling or calendar window of its own,
and a caller may not override its period or its downtime policy per
request; the range is the only thing a request supplies. Availability
over a Prometheus datasource is not supported. Host reachability does
not appear as its own row kind in the timeline; it only ever shows as
time an object's status was unreachable.
