Docket Health Metrics & SLAs
Docket-health metrics are the small set of precisely-defined numbers a docketing team commits to hitting — on-time-completion rate, aging distribution, coverage, acknowledgment latency, and breach count — each paired with a service-level target and an error budget that says exactly how much slack remains before the target is at risk. This page fixes the definitions so tightly that two teams computing the same metric from the same ledger get the same number, then computes them all in one function.
These are the concrete definitions behind the Docket Audit Dashboards & Metrics reference: where that page covers the dashboard architecture and threshold wiring, this one pins the arithmetic and the target values. Every metric is derived from the append-only ledger of the Core Docketing Architecture & Deadline Types reference and reads the effective deadlines the rule engine sealed — it never recomputes a date.
Metric Definitions
A metric is only useful if its definition is unambiguous. The table below fixes each one as a formula over ledger events for a review window. Two definitions carry the most subtlety and cause the most disagreement in practice: the on-time denominator is deadlines due in the window, not deadlines acted on; and coverage’s denominator is the full matter population from matter management, not the set of matters that happen to appear in the ledger.
| Metric | Formula | Notes |
|---|---|---|
| On-time-completion rate | met_on_time ÷ due | due = deadlines whose effective date falls in the window; met_on_time = those met on or before it |
| Breach count | missed + met_late | Absolute count, never a rate; every breach is an incident to review individually |
| Coverage percentage | matters_tracked ÷ matter_population × 100 | Denominator from matter management; surfaces untracked matters |
| Acknowledgment latency (p90) | 90th-percentile(ack_time − first_reminder_time) | Percentile, not mean, so a slow tail stays visible |
| Escalation rate | escalated ÷ due | Share of due deadlines that needed the safety net |
| Aging distribution | count of open deadlines per time-to-due bucket | Bucketed on the effective (rolled) date, keyed by deadline category |
The on-time rate is the headline number, but on its own it is a lagging indicator: it only moves after a deadline has already been missed. The aging distribution and acknowledgment latency are the leading indicators that let a team act before the on-time rate can ever drop — the pressure shows up in the aging buckets and the latency tail first. Reminder timing that keeps deadlines out of the danger buckets is governed by the Deadline Reminder Cadence Engines layer.
SLA Targets & Error Budgets
An SLA target is a commitment, and every commitment implies an error budget — the amount of failure the target tolerates before it is breached. In a legal-deadline domain the budgets are deliberately tiny, because a single missed statutory date can be an unrecoverable malpractice event, but they are not zero: an on-time target of 100.000% is operationally meaningless because it leaves no room to distinguish a system under mild strain from one in crisis. A 99.9% on-time target over a monthly window of, say, 1,000 due deadlines permits exactly one late completion before the budget is exhausted — a threshold tight enough to force review of every near-miss while still being measurable.
| Metric | Target (SLO) | Error budget | Rationale |
|---|---|---|---|
| On-time-completion rate | ≥ 99.9% | 0.1% of due deadlines / month | Every budget-consuming late completion triggers a near-miss review |
| Coverage percentage | 100% of active matters | 0 untracked matters | An untracked matter has no safety net at all; no tolerance |
| Acknowledgment latency (p90) | ≤ 24 hours | p90 headroom to 24h | One business day to confirm receipt of an alert |
| Escalation rate | ≤ 5% of due deadlines | 5% ceiling | A higher rate means owners are relying on the safety net, not working the cadence |
| Breach count | 0 statutory / month | 0 for statutory | Statutory misses are generally unrecoverable; procedural breaches reviewed individually |
The error-budget framing — borrowing the discipline documented in the Google SRE service-level-objectives chapter — turns an abstract target into an operational gauge. When the on-time budget is 60% consumed halfway through a month, the team knows to slow discretionary change and tighten escalation before the budget runs out, exactly as the scorecard above shows. Coverage is the one metric with a genuinely zero budget: an active matter that is not under tracking has no reminder cadence, no escalation ladder, and no safety net, so a single untracked matter is a breach regardless of how the rest of the portfolio looks.
Targets differ by deadline category. A statutory bar date carries a zero breach budget because a miss is generally unrecoverable except through narrow petition mechanisms, while a procedural response with an available extension warrants a small but non-zero tolerance. Bucketing and thresholds are therefore keyed to the category taxonomy in the Core Docketing Architecture & Deadline Types reference, and a threshold breach hands off to the Escalation Routing Workflows layer rather than being resolved on the dashboard.
Computing the Metrics from Ledger Data
One function computes the whole scorecard from a window of ledger entries. It is pure — same entries, same window, same matter population yields the same result — and it reads only the effective deadlines and terminal events the ledger already sealed. It never applies its own date arithmetic.
from __future__ import annotations
import math
from collections import Counter
from dataclasses import dataclass
from datetime import date, datetime
from zoneinfo import ZoneInfo
from pydantic import BaseModel, Field
UTC = ZoneInfo("UTC")
class DeadlineFact(BaseModel):
"""One deadline's terminal facts for a review window, read from the ledger."""
deadline_id: str
matter_id: str
category: str = Field(pattern=r"^(statutory|procedural|discretionary)$")
effective_deadline: date # already rolled off non-working days
due_in_window: bool # effective date falls in the window
outcome: str = Field(pattern=r"^(met_on_time|met_late|missed|open)$")
escalated: bool = False
ack_latency_hours: float | None = None # None if never acknowledged
@dataclass
class DocketHealth:
due: int
on_time_rate: float
breach_count: int
coverage_pct: float
escalation_rate: float
ack_latency_p90: float | None
aging_histogram: dict[str, int]
statutory_breaches: int
def within_slo(self) -> bool:
# The scorecard is green only when statutory breaches are zero, coverage
# is full, and the on-time rate clears its target.
return (self.statutory_breaches == 0
and self.coverage_pct >= 100.0
and self.on_time_rate >= 0.999)
def _p90(values: list[float]) -> float | None:
if not values:
return None
ordered = sorted(values)
rank = min(len(ordered), max(1, math.ceil(0.90 * len(ordered))))
return round(ordered[rank - 1], 2)
def _bucket_label(days: int, boundaries: list[int]) -> str:
if days < 0:
return "overdue"
prev = 0
for b in boundaries:
if days <= b:
return f"{prev + 1}-{b}d" if prev else f"<={b}d"
prev = b
return f">{boundaries[-1]}d"
def compute_docket_health(facts: list[DeadlineFact], matter_population: int,
as_of: datetime, aging_boundaries: list[int]) -> DocketHealth:
"""Compute the full docket-health scorecard from sealed ledger facts."""
if as_of.tzinfo is None:
raise ValueError("as_of must be timezone-aware (UTC)")
today = as_of.astimezone(UTC).date()
due = [f for f in facts if f.due_in_window]
met_on_time = sum(1 for f in due if f.outcome == "met_on_time")
breaches = [f for f in due if f.outcome in ("met_late", "missed")]
escalated = sum(1 for f in due if f.escalated)
tracked_matters = {f.matter_id for f in facts if f.outcome != "open" or f.escalated}
latencies = [f.ack_latency_hours for f in facts if f.ack_latency_hours is not None]
histogram = Counter(
_bucket_label((f.effective_deadline - today).days, aging_boundaries)
for f in facts if f.outcome == "open"
)
n_due = len(due)
return DocketHealth(
due=n_due,
on_time_rate=round(met_on_time / n_due, 5) if n_due else 1.0,
breach_count=len(breaches),
coverage_pct=round(100.0 * len(tracked_matters) / matter_population, 2)
if matter_population else 0.0,
escalation_rate=round(escalated / n_due, 5) if n_due else 0.0,
ack_latency_p90=_p90(latencies),
aging_histogram=dict(histogram),
statutory_breaches=sum(1 for f in breaches if f.category == "statutory"),
)
The function separates the two denominators that cause the most measurement errors: rates divide by due (deadlines whose effective date falls in the window), while coverage divides by matter_population (the full active-matter list from matter management). Mixing them — measuring coverage against the ledger’s matter set, or measuring the on-time rate against deadlines merely touched — is the classic way a scorecard reads healthy while a real gap grows. The statutory_breaches count is broken out separately because it has a zero budget: one statutory breach fails the scorecard regardless of an otherwise perfect on-time rate.
Known Gotchas and Compliance Traps
- A perfect on-time rate hiding a statutory miss. A single missed statutory deadline can be lost in a 99.9% on-time rate over a large portfolio, yet it may be an unrecoverable malpractice event.
statutory_breachesis computed and gated separately so one statutory miss fails the scorecard outright, independent of the aggregate rate. - Coverage measured against the ledger. A matter never docketed produces no ledger facts and silently inflates coverage toward 100%. The coverage denominator is the matter population from matter management, so the untracked matter — the case with no safety net at all — is the one the metric exists to catch.
- Zero-due window returning NaN. A window with no due deadlines must return a defined on-time rate of 1.0 and an escalation rate of 0.0, never divide by zero. A
NaNon a compliance scorecard reads as a broken control and undermines trust in every other number. - Mean latency instead of p90. Averaging acknowledgment latency buries a never-acknowledged tail. The scorecard reports p90 by nearest rank, so a p90 that blows past 24 hours points straight at the owners who are not actioning their alerts.
- Aging by nominal instead of effective date. A deadline that rolls forward over a holiday weekend under 37 CFR 1.7(a) or PCT Rule 80.5 has real extra runway. The histogram buckets on the effective date so the aging distribution reflects genuine urgency, not a nominal date the office would itself extend.
- Error budget treated as a rate to hit rather than spend. The error budget is slack to be consumed deliberately, not a target to run at. A month that consumes 60% of the on-time budget by mid-month is a signal to slow discretionary change, not a licence to keep spending to the ceiling.
Frequently Asked Questions
Why is a 100% on-time target a bad SLA even for legal deadlines?
What is the difference between the on-time denominator and the coverage denominator?
How is an error budget used operationally during the month?
Should docket-health metrics ever recompute a deadline date?
Related
- Docket Audit Dashboards & Metrics — the dashboard architecture and threshold wiring these definitions feed.
- Core Docketing Architecture & Deadline Types — the ledger and deadline-category taxonomy every metric derives from.
- Escalation Routing Workflows — the layer a breached threshold hands off to.
- Deadline Reminder Cadence Engines — the reminder timing that keeps deadlines out of the danger buckets.
↑ Back to Docket Audit Dashboards & Metrics