Module 2: Slis Slos And The Error Budget

7. Hands-on: applying the calculator to a real Andes Cargo scenario

Description

Lessons 4 and 6 ran the calculator over a real month, mostly healthy, with two days of localized degradation. This lesson runs it, without changing a single line of the functions you already built, over a second dataset — seven days, hand-designed to represent a genuinely bad week: a change deployed to process-shipment-manifest that breaks processing for a subset of manifests, detected the same day, but whose full mitigation takes almost the entire week to confirm. The tool needs no code changes for this — that's precisely the point of having built a calculator instead of a one-time calculation like Module 1's.

Connection to the module

This lesson teaches no new function. It reuses budget_report, print_report, and burn_rate_of exactly as they stood at the end of lesson 6, over a different dataset. What's practiced here is reading, not building: facing a real result, with no step-by-step guidance from previous lessons, and knowing how to interpret it with the same judgment. Lesson 8, this module's closing project, is going to cite this lesson's numbers as part of the evidence behind Andes Cargo's real SLO.


The scenario: a bad week, designed with a concrete cause

Day 1 of this week is calm — the system starts in its normal state. On day 2, a change gets deployed to process-shipment-manifest that introduces a parsing error for manifests that include a new field, used by a subset of Andes Cargo's carriers. The error gets detected the same day, day 2 (some manifests start failing), the change gets rolled back, but the rollback doesn't clean up the problem completely right away — some queued manifests keep getting processed with the broken version over the following days, and the team doesn't confirm the error rate is back to normal levels until day 7.

# This is this lesson's new dataset. The functions (budget_report,
# print_report, burn_rate_of) are exactly the same ones from lessons
# 4 and 6, with no changes.
from error_budget_calculator import budget_report, print_report, burn_rate_of

BAD_WEEK = [
    (1, 420, 418),
    (2, 435, 410),
    (3, 410, 379),
    (4, 428, 400),
    (5, 440, 421),
    (6, 300, 292),
    (7, 285, 280),
]

report = budget_report(BAD_WEEK)
print_report(report, "process-shipment-manifest -- bad week (7 days)")

print()
print("--- Daily burn rate ---")
for row in BAD_WEEK:
    br = burn_rate_of([row])
    print(f"Day {row[0]}: valid events={row[1]:>3}  good events={row[2]:>3}  burn rate={br:.2f}x")

print()
print("--- Burn rate for the full week (7-day window) ---")
br_week = burn_rate_of(BAD_WEEK)
print(f"burn rate={br_week:.2f}x")
python3 bad_week_scenario.py

What to expect (literal — the SLO used is still the same reference one, 99.9% monthly, even though the dataset only has 7 days; budget_report always compares against the full window the SLO promises, not against the dataset's number of days, exactly as you confirmed in lesson 4's exercise 3):

--- process-shipment-manifest -- bad week (7 days) ---
Valid events:            2718
Good events:             2600
Measured SLI:            95.6586%
Target SLO:              99.9%
Budget (monthly):        43.2 minutes
Consumed this period:    1875.50 minutes (4341.4% of budget)
Remaining budget:        -1832.30 minutes

--- Daily burn rate ---
Day 1: valid events=420  good events=418  burn rate=4.76x
Day 2: valid events=435  good events=410  burn rate=57.47x
Day 3: valid events=410  good events=379  burn rate=75.61x
Day 4: valid events=428  good events=400  burn rate=65.42x
Day 5: valid events=440  good events=421  burn rate=43.18x
Day 6: valid events=300  good events=292  burn rate=26.67x
Day 7: valid events=285  good events=280  burn rate=17.54x

--- Burn rate for the full week (7-day window) ---
burn rate=43.41x

Reading the result, unassisted: this lesson's real practice

The remaining budget is -1,832.30 minutes. A single week, not a full month, left the monthly budget in a deficit of more than 1,800 minutes — more than 30 hours of "extra" downtime beyond what the SLO allows for the full 30 days. The 4,341.4% of budget consumed means, in other words, that this single week spent more than 43 times an entire month's error budget. This figure, calculated by a generic calculator over a new dataset, lands almost exactly on the same order of magnitude as the Claude Code incident's 33.3x you calculated by hand in Module 1 — a useful coincidence to remember: it doesn't take a catastrophic, 24-hour-uninterrupted incident to consume a month's budget many times over; a week of partial, sustained degradation, with the system running "most of the time," achieves exactly the same kind of damage to the budget.

The daily burn rate pattern tells the incident's whole story, with nobody having to describe it in prose. Day 1 (4.76x) already shows something elevated — this dataset's normal traffic was never perfect — but the real jump happens on day 2 (57.47x), the day of the broken deployment. The peak hits on day 3 (75.61x) — probably the point where the most queued manifests were still being processed with the broken code, before the rollback finished propagating — and from there on the daily burn rate decreases consistently every day (65.42x → 43.18x → 26.67x → 17.54x): the exact numeric signature of a mitigation that's working, gradually, instead of one that fails and stalls. Not even day 7, the week's best day, manages to drop below 17x — the full week ends without yet returning to a healthy burn rate (close to 1x or lower), even though the trend is clearly positive.

The full window's burn rate (43.41x) isn't the simple average of the seven daily values. Worth noting why: burn_rate_of over the full window recalculates the error rate by adding up all valid and good events across the seven days together, it doesn't average seven already-calculated separate numbers — higher-traffic days (for example, day 5, with 440 valid events) weigh more in that aggregate calculation than lower-traffic days (day 7, with 285). This is the same logic behind compute_sli you've used since lesson 4: sum events, don't average already-calculated rates — a distinction that matters because averaging rates directly can give a slightly different, and generally less correct, result than aggregating the raw events first.


Common mistakes

Interpreting "-1,832.30 minutes" as a calculation error because "there can't be a negative budget" (repeated from lesson 5, at a larger magnitude). What happens: someone, seeing such a large deficit, assumes the script has a bug. How to spot it: if your reaction is to distrust the number instead of reading it as "how far over budget this went." How to fix it: you already saw in lesson 5 that a budget can be consumed above 100% — this lesson simply carries that same arithmetic into a more severe scenario. The negative number is real information: it quantifies, in minutes, how far beyond the allowed limit this specific week went.

Assuming the day-over-day decreasing burn rate means the system was already back to normal by day 7 (reading only the trend, not the absolute value). What happens: someone sees the sequence 75.61x → 65.42x → 43.18x → 26.67x → 17.54x and concludes "the problem is basically over, the system is healthy." How to spot it: if your conclusion about day 7 doesn't mention that 17.54x is still seventeen times faster than what the SLO allows. How to fix it: a positive trend (burn rate dropping every day) isn't the same as a healthy value (burn rate near or below 1x). Day 7 of this dataset is still far from 1x — the improvement is real, but the system, per this reading, still hadn't returned to a normal error rate by the time the week this dataset covers ends.

Manually recalculating the full window's 43.41x as the average of the seven daily values (applying the wrong formula). What happens: someone adds up the seven daily burn rate values and divides by 7, expecting to get 43.41. How to spot it: if your manual calculation doesn't match the script's output. How to fix it: the simple average of this lesson's seven daily values gives a different number (closer to 41) because it doesn't weight by each day's number of valid events — burn_rate_of over the full window sums all events first (2,718 valid, 2,600 good) and calculates a single burn rate over those aggregate totals, not an average of already-separately-calculated rates. It's the same distinction, applied here, between "averaging ratios" and "summing numerators and denominators separately before dividing" — the second is, almost always, the correct one when days have different traffic volumes.


Exercises

Exercise 1 — Calculate by hand how many times this week consumed the full monthly budget, using only the report's percentage. The report says "4341.4% of budget." Express it as a multiple, in the same format as Module 1's 33.3x.

See solution

4,341.4% equals 4,341.4 / 100 = 43.414 times the full monthly budget — matching, as expected, the full window's burn rate=43.41x the script already calculated separately (with a small rounding difference between the two ways of reading it, both correct). In the same format as Module 1: this single week consumed the equivalent of 43.4 months of error budget, in just 7 days — a consumption pace that's, in relative terms, even faster than the Claude Code incident itself (33.3x, but over 24 hours of near-total downtime, not a week of partial degradation).

Exercise 2 — Identify, without running anything, on which day the daily burn rate would last cross Google's "Page" threshold (14.4x, the most urgent row of lesson 6's Table 5-8) before dropping below it. Use the values already printed in this lesson's "What to expect."

See solution

The daily values, in order: 4.76x (day 1), 57.47x (day 2), 75.61x (day 3), 65.42x (day 4), 43.18x (day 5), 26.67x (day 6), 17.54x (day 7). The 14.4x threshold is crossed upward between day 1 and day 2, and it stays above 14.4x on every following day, including day 7 (17.54x > 14.4x) — this week, per this lesson's dataset, never drops back below Google's most urgent threshold on any complete day the dataset covers. This reinforces the "Reading the result" section's reading: the trend is positive, but the system still hadn't reached, by day 7, even the "Page" severity level on the way down — let alone a healthy burn rate near 1x.

Exercise 3 — Explain, using this scenario, why this guide designed a "bad week" instead of reusing the same two-day incident type from days 17-18 of lesson 4's dataset. What does this second dataset teach that the first one couldn't?

See solution

The days 17-18 incident (lesson 4) was sharp and brief: two days of clear degradation, followed by a complete, immediate recovery (day 19 returns to zero errors, as lesson 6 confirmed). This second dataset teaches a different pattern that, in many real systems, is more common: degradation that does not resolve all at once, but improves gradually over several days, while the system keeps, technically, "working" (it never drops to zero good events on any single day). This pattern is harder to read with a single summary figure — "is it fixed or not?" has no clear binary answer while the burn rate is still dropping from 75x to 17x without reaching 1x — and it's exactly the kind of scenario where having a daily burn rate, not just the month's cumulative SLI, turns out to be more useful: it lets you see a mitigation's entire trajectory in progress, not just whether it's over or not.


Summary and next step

In this lesson you ran the complete calculator — with no function changes at all — over a second dataset: a hand-designed week with a concrete cause (a broken deployment, rolled back the same day, with a mitigation that takes the whole week to confirm). The result: an SLI of 95.66%, a budget deficit of -1,832.30 minutes, and a daily burn rate pattern that tells the incident's whole story — a peak of 75.61x on day 3, decreasing consistently to 17.54x on day 7, without yet reaching a healthy level. You practiced reading a real result with no step-by-step guidance from previous lessons, and confirmed that 43.4 times the monthly budget, consumed in a single week of partial degradation, is on the same order of magnitude as a 24-hour catastrophic incident's 33.3x.

Before moving on you should be able to: run the calculator over a new dataset without modifying any existing function; read a budget deficit of several thousand minutes without distrusting the result; and explain why a decreasing daily burn rate isn't the same as a system that has already recovered.

Lesson 8 closes this module with SLO.md: the document that gathers all the evidence from the seven previous lessons — lesson 3's SLI definition, lesson 5's candidate SLO, lessons 6 and 7's burn rate behavior — into the formal decision the rest of this guide is going to measure and cite, without reopening the discussion.

Resources

  1. This same repository, Module 2, lessons 4 and 6 (04-hands-on-the-error-budget-calculator.md, 06-hands-on-burn-rate-not-just-the-balance.md) — the functions this lesson reuses unchanged.
  2. This same repository, Module 1, lesson 6 (06-hands-on-the-error-budget-the-claude-code-incident-burned.md) — the 33.3x this lesson's 43.4x is compared against.
  3. Google SRE Workbook — Alerting on SLOs — the source for burn rate, applied here to a second real scenario.