See it as a diagram
Everything below, as a diagram you can edit. Describe yours and see it in seconds.
No account needed · Editable canvas, not a picture
Three words that are not synonyms
The indicator (SLI) is a measurement with a definition precise enough that two people compute the same number: minutes between the newest placed_at value and the current time, sampled at the output port every fifteen minutes. Ambiguity here poisons everything downstream, because a freshness measured at load start and one measured at commit differ by exactly the duration of the load.
The objective (SLO) is the target for that indicator over a window: freshness under two hours for 99 percent of measurements in a rolling thirty days. Note the two numbers. A target without a window and a percentile is a wish, since any threshold is met sometimes.
The agreement (SLA) is the consequence: who is told, how fast, what the fallback is, and what the producer commits to doing. Inside one company there are rarely financial penalties, so the meaningful content is the escalation path and the remediation commitment. An SLA with no consequence section is an SLO with a formal tone.
The four indicators worth committing to
Freshness: the age of the newest record at the output port. It is the indicator consumers notice first and the one that most often has a real business deadline behind it, such as a report that must be right by 9am.
Completeness: the share of expected records present, measured against a countable expectation such as the source row count or a known daily range. Vaguer than freshness, so define the expectation explicitly or do not commit to it.
Correctness: the pass rate of a named, versioned set of quality checks. The trick is that the check set has to be named in the agreement, because "the data is correct" is unmeasurable while "these eleven checks pass" is not.
Availability: the output port responding and queryable. Usually inherited from the platform rather than owned by the domain, which is worth stating so the domain is not held to a warehouse outage.
How to pick the number
Measure first, for at least thirty days and preferably ninety, with no target set. You need the shape of the distribution, not the average: batch pipelines are heavily tailed, and the mean load time tells you almost nothing about the bad Monday.
Set the objective at roughly the observed p95, then round to something a human can remember. If ninety-five percent of loads land within ninety-four minutes, promise two hours. Promising the observed best case guarantees a miss in the first month and teaches consumers that the number is decorative.
Give yourself an error budget and compute it rather than feeling it. Sampling every fifteen minutes for thirty days is 2,880 measurements; a 99 percent objective allows 28 of them to be out of target, and since each failing sample stands for a fifteen-minute window that is about seven hours of lateness across the month. Seven hours sounds generous until a single stuck load consumes five of them in one morning. When the budget is spent, reliability work takes priority over the next feature; when it is never touched, the target is too loose and can be tightened. Without the budget, every individual miss becomes an argument.
Set the objective per output port, not per product. The Kafka topic and the warehouse table for the same product have genuinely different latencies, and one number covering both will either be dishonest about one or too loose for the other.
Writing it down where it will be read
The service level belongs in the data contract, next to the schema, and travels through the same pull request as the code that has to keep it. Service levels stored in a wiki page drift within a quarter, for the same reason contracts stored in a separate repository do.
Publish the measurement alongside the promise. A dashboard showing the indicator against the objective for the last thirty days ends most of the disputes before they start, because the disagreement is usually about what actually happened rather than about what was promised.
Keep the notice period separate from the SLA. Freshness and completeness are about the running system; the notice period before a breaking change is about the contract's evolution. Both live in the contract, and confusing them leads to a schema change being announced as an incident.
-- The SLI, defined so two people compute the same number.
-- Measured at the output port, on the business timestamp, not on load time.
select
datediff('minute', max(placed_at), current_timestamp()) as freshness_minutes
from analytics.checkout.orders_fct;
-- The SLO over the window, from the samples you have been storing.
-- One row per 15-minute probe of the query above.
select
count(*) as samples,
count_if(freshness_minutes <= 120) as within_target,
round(100.0 * count_if(freshness_minutes <= 120)
/ count(*), 2) as attainment_pct,
count_if(freshness_minutes > 120) as budget_spent,
greatest(0, floor(count(*) * 0.01)
- count_if(freshness_minutes > 120)) as budget_left
from platform.sli.freshness_samples
where port = 'snowflake://analytics/checkout/orders_fct'
and measured_at >= dateadd('day', -30, current_timestamp());The map you need when the budget is burning
FAQ
What is a data SLA?
What is the difference between SLI, SLO and SLA for data?
How do you set a data freshness SLA?
Should the SLA live in the data contract?
What is an error budget for a data pipeline?