« Phase 14 · Warmup · Track Overview

Lab 01 — The SRE Console

The problem

It is 03:12. Your phone goes off. Availability is 99.97% against a 99.5% target, latency p99 is normal, error rate is flat, CPU is at 40%.

And the platform is broken:

  • One tenant's agent has been in a retry loop since 23:00 and has spent 340% of its monthly budget. Every request succeeded.
  • A guardrail change is refusing 60% of retrieval, so answers are being generated from nothing. Every request succeeded.
  • The provider quietly moved the model behind a stable version string, and the eval score dropped 0.14. Every request succeeded.

None of the four golden signals moved, because none of these are errors. That is what "tuned for non-deterministic AI workloads" means: correctness is a distribution, cost is a first-class signal, and the thing you page on is not the thing that is wrong.

You build the console that would have caught all three — and, harder, that does not page for the one failure out of two requests on a service nobody uses.

What you build

#ComponentWhat it does
1ValidityPredicatethe denominator, as an explicit design decision
2availability_sli, latency_slithe event-ratio model; latency as a ratio, not a percentile
3ErrorBudget, allocate_budgetrolling budgets that clamp at zero and report overspend separately
4burn_rate_thresholdderives 14.4 instead of memorizing it
5BurnRateAlertingtwo windows per rule, plus the minimum-volume guard
6SpanTreean OTel-shaped run tree, and self time with interval union
7CardinalityBudgetrejects an unaffordable metric at definition time
8DegradationLadderdescend fast, ascend slowly, with hysteresis
9cost_report, CostCircuitBreakercost per successful action; per-tenant trip
10forecast_capacityprovider quota, projected, with procurement lead time
11classify_regressionmodel vs prompt vs corpus — only answerable if pinned

Key concepts

ConceptWhereWhy it matters
The denominator is the argumentValidityPredicatesix events, three predicates, three different SLIs
Safety blocks: not good, still validGOOD_OUTCOMESelse a guardrail refusing everything shows green
Synthetic probes are excludedexclude_syntheticotherwise you improve the SLO by probing more
An empty window is 1.0availability_slizero traffic is not an outage
Latency as a ratiolatency_slipercentiles do not average and have no budget
Budgets clamp at zeroBudgetStatea dashboard showing −340% helps nobody
Overspend is reported separatelyoverspent_by"how far past" is still a real question
Allocation gives it an ownerallocate_budgeta shared budget is a budget nobody owns
14.4 is derivedburn_rate_threshold0.02 / (1/720); not a magic number
Two windowsBurnRateAlertingthe short window is the reset
The minimum-volume guardmin_events1-in-2 is a 100× burn rate and must not page
Self time, not totalSpanTree.self_timetotal blames the root for everything
Union, not sum, of childrenself_timeconcurrent children would give negative self time
GenAI semantic conventionsSpan.attributesso any OTel backend charts tokens without custom queries
Series are a productMetricSpec.series_countone label multiplies everything; a cliff, not a slope
Unbounded labels are forbiddenFORBIDDEN_LABELSids belong on traces, not on metrics
Rejected at definition timeregisterthe backend falls over during an incident, not before
Descend fast, ascend slowlyDegradationLadderand hysteresis, or the quality flaps
Degradation must be visibleuser_visiblea silent quality change is how trust is lost
Cost per successful actioncost_reportcost per request improves when you fail faster
A cost control is an availability controlCostCircuitBreakerthe runaway looks like success everywhere else
Per-tenant tripcheckone loop must not exhaust anyone else's budget
The limit is the provider quotaforecast_capacityyou hit TPM long before CPU
Alert a lead time earlysafety_factora 90% alert arrives after the decision point
Pinning is the techniqueBaseline"nothing we control changed" is only sayable if you pinned

Files

FileRole
lab.pyyour implementation
solution.pyreference; python solution.py runs an eleven-part worked session
test_lab.py132 tests
requirements.txtpytest

Run

pip install -r requirements.txt
pytest test_lab.py -v
LAB_MODULE=solution pytest test_lab.py -v
python solution.py

Success criteria

  • All 132 tests green against your lab.py.
  • A safety block is valid but not good; a client error is neither.
  • An empty window scores 1.0, not 0.0.
  • latency_sli is inclusive at the threshold, and a fast failure is still not good.
  • burn_rate_threshold(0.02, 1.0) == 14.4, derived.
  • An alert fires only when both windows agree.
  • A recovered short window stops the alert while the long window is still hot.
  • One failure in two requests does not page, and the reason names the minimum.
  • The budget never goes negative, and overspend is a separate number.
  • Two fully-concurrent children do not produce zero self time for their parent.
  • Total self time across all spans equals the root's duration.
  • A metric with user_id is rejected regardless of its estimated size.
  • A rejected metric is not registered.
  • The ladder jumps straight to level 3 at a 20× burn rate, and ascends one rung at a time.
  • Recovery holds for the configured period before ascending.
  • Cost per action doubles when half the requests fail.
  • One tenant tripping the breaker leaves another allowed.
  • A tenant with no configured budget is denied.
  • The same growth curve alerts or not depending only on the lead time.
  • A regression with every version unchanged yields the provider-or-drift hypothesis.

How this maps to the real stack

This labThe real thingWhat we simplified
RequestEventa metrics pipeline (Prometheus, Azure Monitor)in-memory events; no scraping, no aggregation, no downsampling
availability_slia recording rule over a counterno rate(), no window alignment, no staleness handling
BurnRateAlertingPrometheus alerting rules, or Azure Monitorno for: duration, no inhibition, no routing or on-call
SpanTreeOpenTelemetry + Jaeger/Tempo/App Insightsno context propagation, no sampling, no exporter
Span.attributesOTel GenAI semantic conventionsa subset; no events, no links, no resource attributes
CardinalityBudgetPrometheus scrape_limit, Mimir per-tenant limitsestimates, not measured series
DegradationLaddera feature-flag system plus routing policyno actual shedding; the order is the point
CostCircuitBreakerthe gateway's quota ledger (Phase 04)no enforcement path
forecast_capacitya capacity model over provider quota metricsa linear fit; no seasonality, no confidence interval
classify_regressionan eval pipeline plus a deployment manifestversions as strings; no actual eval

Honest limits. The forecaster fits a straight line — which is exactly wrong for the traffic an AI platform actually sees, where adoption is closer to exponential and demand is strongly diurnal. A real one needs seasonality and a confidence interval, and reporting a point estimate without one overstates what it knows. The alerting has no for: duration and no inhibition, so a real deployment would still fire three alerts for one incident. The cardinality budget works from estimates, and the estimate for tenant is wrong the day someone onboards a customer per branch. Spans have no sampling, which is the decision that actually determines whether tracing is affordable — at 100% sampling an agent platform generates more trace data than log data. And the degradation ladder does not shed anything; it decides what would be shed and in what order, which is the part that has to be decided in daylight.

Extensions

  1. Add sampling. Head-based, then tail-based (keep every errored or slow trace, sample the rest). Then answer: what is the storage cost at 100%, at 10%, and what did you lose?
  2. Seasonality in the forecaster. Fit weekly and daily components. Compare the projection against the linear one on real-shaped data and see how different the procurement date is.
  3. for: durations and inhibition. Make one incident produce one page instead of three.
  4. A quality SLO, properly. Sampled offline evaluation as a gated objective: it blocks deploys and is reviewed weekly, and it never pages. Then defend that choice.
  5. Burn rate on cost. The same multi-window machinery against a spend budget rather than an error budget. Most of the code is identical, which is the interesting part.
  6. Exemplars. Link a metric bucket to a trace id, so "p99 is bad" becomes "here is a p99 trace". It is the single highest-value observability feature most teams have not enabled.
  7. A real post-mortem template, generated from the console: the timeline from alerts, the budget consumed, the degradation steps taken, the traces at the p99.
  8. Multi-region SLIs. Compose per-region SLIs into a global one, and discover that the ratio composes cleanly while the percentile does not — which is the argument in §2, demonstrated.

Interview / resume bullets

  • "Defined the platform's SLIs on an explicit event-ratio model with a written validity predicate, which turned every SLO argument from a disagreement about numbers into a disagreement about the denominator — where it belongs."
  • "Kept answer quality out of the availability SLO and ran it as a gated objective instead: it blocks deploys and is reviewed weekly, but it never pages, because a distribution shift is not an incident."
  • "Implemented multi-window multi-burn-rate alerting with derived thresholds and a minimum-volume guard, which cut 3 a.m. pages on low-traffic services to zero without raising a single threshold."
  • "Made cost per successful action and safety-block rate first-class signals, and added a per-tenant cost circuit breaker — which caught a runaway agent loop that every traditional signal reported as healthy."
  • "Instrumented agent runs as OTel span trees with GenAI semantic conventions and self-time attribution, so 'the platform is slow' became 'the reranker is 690 ms of the 4.1 s' in one query."
  • "Enforced a cardinality budget at metric-definition time, which prevented the label that would have taken the metrics backend down during an incident."
  • "Forecast capacity against provider quota rather than utilization, with alerts sized to procurement lead time — so a GPU quota conversation started at 55% utilization instead of at a hard 429."