SLA compliance¶
What share of tickets did we resolve within the time we promised?
Current value (service case data): 94.4% - ✓ On target. Open the case.
| Field | Value |
|---|---|
| Definition | Resolved tickets whose resolution time is within the SLA target of their priority, divided by all resolved tickets. |
| Formula | count(resolution_hours <= sla_target_hours) / count(resolved) |
| Unit | % |
| Granularity | Ticket; reported weekly and monthly by priority and queue. |
| Direction | Higher is better ↑ |
| Target and thresholds | ≥ 90.0% (amber ≥ 85.0%) |
| Parameters | – |
| Owner | Service Desk Manager |
| Source | Ticketing system (synthetic generator) |
| Input | table tickets, columns status, resolution_hours, sla_target_hours |
| Recommended chart | bullet - Value against target and amber band in one glance; per queue as small bullets. |
| Related KPIs | Resolution time (median), Aged backlog (> 7 days) |
How to read it¶
The promise kept. A drop means customers felt it already; look at aged backlog to see the drop coming two to three weeks earlier.
Common misreadings¶
- A lagging indicator - it is measured at closure, so tickets breaching right now are not in it yet.
- Pausing the SLA clock ("waiting for customer") without auditing the pauses inflates compliance.
- An overall figure averages P1 and P4; a 95% fleet number can coexist with a broken P1 promise.
Worked example (from the test suite)¶
| ticket_id | status | first_response_hours | resolution_hours | sla_target_hours | contacts | reopened | age_days |
|---|---|---|---|---|---|---|---|
| 1 | resolved | 1.0 | 10.0 | 24.0 | 1 | False | – |
| 2 | resolved | 3.0 | 30.0 | 24.0 | 2 | False | – |
| 3 | resolved | 0.5 | 4.0 | 8.0 | 1 | True | – |
| 4 | resolved | 6.0 | 50.0 | 72.0 | 1 | False | – |
| 5 | open | – | – | 24.0 | 1 | False | 9.0 |
Expected result: 75.00%. Within SLA: #1 10<=24 yes, #2 30<=24 no, #3 4<=8 yes, #4 50<=72 yes. 3 of 4 resolved = 0.75. The open ticket is not counted.
This example is asserted in tests/test_formulas.py against the Python function and in tests/test_sql.py against the SQL below.
Implementations¶
Python function (the single implementation used by the site):
@kpi("sla_compliance")
def sla_compliance(df: pd.DataFrame) -> float:
r = _resolved(df)
return safe_ratio((r["resolution_hours"] <= r["sla_target_hours"]).sum(), len(r))
Reference SQL (tested on SQLite):
SELECT CAST(SUM(CASE WHEN resolution_hours <= sla_target_hours THEN 1 ELSE 0 END) AS REAL) / COUNT(*)
FROM tickets WHERE status = 'resolved'