The starting point of a policy is an SLI that already exists
Publishing an SLO and putting 99.x% on a dashboard does not create a deployment gate. To become a real measure, one operating policy has to settle which user outcome is measured, what level is targeted, which period is evaluated, which kinds of change are restricted at what level of budget use, and who approves exceptions. Google SRE draws this line clearly.[2] Unless an organization agrees to use the error budget in real decisions and work priorities, the SLO stays another reporting number.
Starting from the target inverts the order. You first define the important user journeys and decide which events count as success and failure. The policy needs eight inputs from that earlier stage.
One more condition attaches here. While the SLI itself cannot be trusted, the error budget cannot be a deployment measure either. If broken instrumentation is treated as 100 percent healthy, or a large share of real requests has disappeared from the denominator, then "plenty of budget left" is a meaningless calculation. So the policy needs a state for whether measurement is trusted, not only for the budget.
- Critical user journey
- Why the policy needs it: Fixes which user outcome is being protected
- Good and valid events
- Why the policy needs it: Sets the numerator and denominator of the target and the error budget
- Exclusion rules
- Why the policy needs it: Keeps user cancellations and malformed requests from counting as service failure
- Measurement point
- Why the policy needs it: Tells you the distance between real user experience and the measured value
- Coverage evidence
- Why the policy needs it: Prevents missing instrumentation from being read as healthy
- Critical segments
- Why the policy needs it: Checks whether an overall average hides the failure of one user group
- Unknown or stuck handling
- Why the policy needs it: Stops requests with unknown outcomes from being counted as successes
- Deployment version linkage
- Why the policy needs it: Lets you investigate the relationship between budget burn and a specific change
Do not start by writing 99.9 percent
The target is not a number that decorates a service tier. Google SRE asks for three conditions together.[2] Product has to agree that below that level, engineering time is worth spending on users. Development has to agree to actually change behaviour when the budget runs out. And the operations owner has to be able to defend the target without excessive toil or burnout.
So setting 99.9 percent as a default and attaching the reason later is best avoided. Setting a target means answering at least six questions. How much failure in this journey do real users feel? Is this a journey with high failure cost — money, data, permissions, work stoppage? What is the current indicator, and can that measurement be trusted? Can the target be held under normal operating conditions? Does the added cost and operational complexity of a higher target give users real value? And is the current target so loose that the policy only fires after substantial user harm?
You do not need the perfect number at the start either. Google SRE recommends measuring an initial target and revising it iteratively.[2] If a higher target you cannot yet meet is needed, track it separately as an aspirational SLO, kept distinct from the operational SLO that triggers the error budget policy immediately. In short, a target needs not only a number but a reason for that number.
Operations connected from observation to improvement — Respond using service indicators and alerts, then connect change records and incident reviews to improvements.
The evaluation window is part of the policy
The same target produces different decisions depending on the period you look at. Google SRE distinguishes rolling windows from calendar-aligned ones.[2] A rolling window fits user experience, since an outage at month end does not vanish from users' memory merely because the first of the next month arrived. A calendar window is easier to tie to the organization's planning cycle, such as quarterly staffing and project plans.
Google offers a four-week rolling window as a general starting point but does not impose it as a standard. Short windows suit fast operational adjustment; long ones suit larger reliability investment decisions. So the policy records the window type and length, the operational review cadence used for deployment and change decisions, the longer planning review cadence for reliability investment priorities, and the reason this window fits the user experience and the business cycle.
28 days, 30 days, and a month look similar but do not always mean the same thing. On a service where weekday and weekend traffic differ sharply, or where month-end work concentrates, choosing the window itself changes the indicator's result.
An error budget is not always "so many minutes of downtime"
The base concept is simple: the budget is one minus the target. But the unit of actual consumption depends on how the indicator is computed.
If the success-rate target is 99.5 percent over 200,000 valid requests, the window allows 1,000 bad events. Allowed bad events are valid events multiplied by one minus the target; budget consumption is actual bad events divided by allowed bad events. Here the error budget is read in failed events, not in minutes of downtime. If instead the target divides time into slices and judges each slice good or bad, it is bad time slices that consume the budget.
Current cloud provider documentation also separates request-based from windows-based indicators. OpenSLO v1 names the budgeting method explicitly as occurrences, timeslices, or ratio timeslices.[1] The policy template should record not only the target but the budgeting method and the consumption formula. In particular, if you evaluate a request-based target mid-window while traffic changes the denominator, exactly how many events the final error budget contains may not be settled yet. Google SRE notes that in a calendar window with unknown future request volume, mid-window judgement carries this uncertainty.[2]
Set the policy state, not the remaining number
A dashboard carries several numbers: SLO compliance, allowed error budget, budget used, budget remaining, recent consumption, and burn rate. The problem is when none of them turns into an action. In an operating policy it is easier to convert numbers into four policy states.
There is no reason for every organization to use the same threshold for entering CONSTRAINED. A team can set conditions such as remaining budget percentage, the likelihood of exhaustion before the window closes, or a single event of a certain size. But that value should come from the service's deployment frequency, traffic pattern, failure harm, and response capacity, rather than from a template found online.
How fast budget consumption is computed and when it is delivered as a page, a ticket, or a dashboard is an alerting design question. Here we stop at which states the policy needs.
Policy state | Meaning | Default operating stance |
|---|---|---|
| NORMAL | Budget is sufficient within the agreed range | Change under the existing release policy |
| CONSTRAINED | Headroom has shrunk, or the current burn trend is risky | Reduce high-risk change and raise the evidence and approval bar |
| EXHAUSTED | The window's error budget is fully consumed | Restrict by default any change that adds risk before reliability recovers |
| MEASUREMENT_UNTRUSTED | SLI coverage or data quality makes the budget untrustworthy | No automatic approval — apply manual judgement or a conservative change policy |
An exhausted budget does not make every deployment equally risky
The most dangerous simplification in an error budget policy is the one line: budget means deploy, no budget means no deployment at all. Real changes carry different purposes and different risks. Combining budget state with change class is more workable.
The point of the table is not that every company should operate identically. What has to be decided is which kinds of risk you accept less of as the budget falls. Google's example error budget policy also restricts feature change on exhaustion while carving out P0 and security fixes.[3] It further notes that for an SLO miss caused by a dependency there are two defensible approaches — continue internal releases, or apply a change freeze to prevent further incidents — and asks that the choice fitting your service be written into the policy.
EXHAUSTED is more accurately read as a state where the default tolerance for changes that add user risk has dropped, not as "touch nothing". Whether a change is executed as pause, flag off, traffic drain, rollback, or forward fix is a separate matter; the rollback design that handles code, configuration, database, data, feature exposure, and traffic together owns that execution contract.
Change class | NORMAL | CONSTRAINED | EXHAUSTED |
|---|---|---|---|
| New feature or experiment | Standard release policy | Reduce blast radius, add review, or defer | Restricted by default |
| Routine config or infrastructure change | Proceed normally | Re-examine necessity and change risk | Defer unless urgent |
| High-risk database or data change | Separate high-risk change policy | Apply conservatively as a rule | Restricted by default |
| Reliability fix | Proceed normally | Raise priority | Perform first where needed |
| Security or emergency fix | Proceed according to risk | Weigh delay risk against change risk | Perform under the pre-defined exception and approval path |
| Incident mitigation or rollback | Perform as needed | Perform as needed | Perform to restore service |
Reliability work belongs in the policy too
Writing only "feature freeze" and "we will stabilize meanwhile" leaves actual work priorities vague. You also have to define which reliability work starts when the budget burns fast or runs out.
Eight examples: analysing the failure class that consumed most of the budget; fixing recurring reliability bugs; mitigating risky dependencies; strengthening test or deployment verification; automation that shortens recovery; resolving capacity and resource saturation; correcting a badly defined indicator or event classification; and removing the structural cause that keeps forcing exceptions. Google SRE also describes using the error budget to prioritize reliability projects.[2] For the same staffing, pick the work that will cut actual budget burn the most.
Here too there is no need to make a universal rule such as "on exhaustion the whole team does only reliability work". What the policy must set is the trigger, the change in reliability work priority, the owner, the minimum condition to complete, and the exit criteria for leaving that policy state. In a rolling window, past failures fall out of the window over time and the budget can recover on its own. Releasing every restriction automatically merely because the number returned to a normal range leaves the cause in place. For a material miss, make it an exit criterion that measures reducing the chance of recurrence were carried out alongside budget recovery.[3]
Exceptions are not negotiated after an incident
An error budget policy is needed most when the original plan collides with reality. There may be a security fix that must ship immediately while no budget remains. A deployment may be needed to mitigate an outage in the current version, or a new change may be required to prevent data loss. If every such moment starts a debate from scratch about deploying "just this once", the policy is not reducing decision cost.
Allowing many exceptions is not the goal. Conversely, exceptions needed repeatedly are a signal that the existing target or change policy does not match real operations. In that case, revisit the policy itself rather than keep adding exceptions.
Field | What to record |
|---|---|
| Eligible exception | Which situations qualify as candidates |
| Requester | Who asked for the exception |
| Reason | Why applying the current policy as-is creates greater risk |
| User impact | The harm users face if this is delayed |
| Change risk | The risk the change itself adds |
| Mitigation | How blast radius and failure impact will be bounded |
| Approver | Who holds final override authority |
| Expiry | How long the exception remains valid |
| Evidence | The data used at the time of approval |
| Post-change review | When the outcome and extra budget burn will be reviewed |
Naming one SLO owner is not enough
The error budget is not a number between the development team and the operations team. Google SRE says the product manager, the development team, and the production owner all have to agree on the policy, and recommends recording author, reviewer, approver, and next review date in the SLO document.[2] An escalation path for disagreement about applying the policy is needed too. In practice, responsibility divides into six roles.
In a small team one person can hold several roles. What matters is not the number of titles but that it is unambiguous who computes the numbers, who can restrict deployment, and who approves exceptions.
- Service or product owner
- The service or product owner approves whether the target is appropriate, judged by user harm and business need.
- SLO owner
- The SLO owner maintains the definitions of the SLI, target, window, and budget calculation, and the trustworthiness of the data.
- Engineering or change owner
- The engineering or change owner applies the actual change policy and enforces the restricted state.
- Reliability work owner
- The reliability work owner manages the causes of budget burn and the priority of reliability work.
- Exception approver
- The exception approver authorizes a policy override and records the reason for it.
- Escalation owner
- The escalation owner makes the final call when there is disagreement over the budget calculation or the policy's application.
Set the review cadence in advance too
Services change. Traffic mix shifts, customers change, dependencies are replaced, and a user journey that once did not matter becomes a core feature. Approve an SLO once and use it unchanged for years, and the originally sensible target becomes a wrong operating measure.
Google SRE suggests reviewing relatively often — monthly, say — when starting out with SLOs, then extending to quarterly or longer once fitness is confirmed.[2] More recent discussion of rethinking SLOs likewise argues that on complex services you should not apply an SLO too broadly, but define it narrowly around the question it answers, and keep validating it as service behaviour and workload change.
It is worth adding event-driven review conditions alongside the calendar ones: the critical user journey changed; the indicator's events or measurement point changed; a major dependency was replaced; user, tenant, or region mix shifted substantially; deployment frequency or the change model changed; policy exceptions recurred; the SLO is met but users keep complaining about reliability; and the SLO is missed repeatedly with almost no user impact. The last two matter most. If the SLO has lost its correlation with real user experience, tightening the target is not enough — the indicator itself needs re-examination.
What goes in the policy template
The numbers in the template are filled in by the organization. Do not put 99.9 percent, 30 days, or any particular budget threshold in as a default. The template divides into eight blocks.
Fill in policy identity, SLI inputs, SLO target and window, and budget calculations in the corresponding fields.
Use the same form for policy states, permitted and restricted changes, reliability work, exceptions, ownership, and review. Event-driven triggers and review questions retain every original item.
Much of this template can be automated. Indicator computation, budget consumption, change gate integration, and approval records can all move into systems. But some values a system cannot set for itself. What level of failure is unacceptable to users, which risk to give up when the budget is short, and whether delaying a security patch is more dangerous than shipping it all need the organization's service responsibility and product judgement.
Field path | Value or allowed values |
|---|---|
| policy.name | "" |
| policy.service | "" |
| policy.critical_user_journey | "" |
| policy.scope | "" |
| policy.status | draft | active | suspended |
| policy.authors | [] |
| policy.reviewers | [] |
| policy.approvers | [] |
| policy.approved_at | "" |
| policy.next_review_at | "" |
| sli_input.specification | "" |
| sli_input.good_event | "" |
| sli_input.valid_event | "" |
| sli_input.bad_event | "" |
| sli_input.excluded_event.definition | "" |
| sli_input.excluded_event.rationale | "" |
| sli_input.unknown_event_policy | "" |
| sli_input.measurement_point | "" |
| sli_input.minimum_measurement_coverage | "" |
| sli_input.critical_segments | [] |
| sli_input.deployment_version_correlation | "" |
| slo.target | "" |
| slo.target_rationale | "" |
| slo.type | operational | aspirational |
| slo.window.type | rolling | calendar_aligned |
| slo.window.duration | "" |
| slo.window.rationale | "" |
| budgeting_method.type | occurrences | timeslices | ratio_timeslices |
| budgeting_method.calculation | "" |
| error_budget.allowed_budget_calculation | "" |
| error_budget.consumption_calculation | "" |
| error_budget.data_source | "" |
| error_budget.dashboard_or_report | "" |
| policy_states.NORMAL.trigger | "" |
| policy_states.NORMAL.exit_condition | "" |
| policy_states.CONSTRAINED.trigger | "" |
| policy_states.CONSTRAINED.exit_condition | "" |
| policy_states.EXHAUSTED.trigger | "" |
| policy_states.EXHAUSTED.exit_condition | "" |
| policy_states.MEASUREMENT_UNTRUSTED.trigger | "" |
| policy_states.MEASUREMENT_UNTRUSTED.fallback_decision_rule | "" |
| policy_states.MEASUREMENT_UNTRUSTED.exit_condition | "" |
| change_policy.feature_or_experiment.NORMAL | "" |
| change_policy.feature_or_experiment.CONSTRAINED | "" |
| change_policy.feature_or_experiment.EXHAUSTED | "" |
| change_policy.routine_config_or_infrastructure.NORMAL | "" |
| change_policy.routine_config_or_infrastructure.CONSTRAINED | "" |
| change_policy.routine_config_or_infrastructure.EXHAUSTED | "" |
| change_policy.database_or_data_change.NORMAL | "" |
| change_policy.database_or_data_change.CONSTRAINED | "" |
| change_policy.database_or_data_change.EXHAUSTED | "" |
| change_policy.reliability_fix.NORMAL | "" |
| change_policy.reliability_fix.CONSTRAINED | "" |
| change_policy.reliability_fix.EXHAUSTED | "" |
| change_policy.security_or_emergency_fix.NORMAL | "" |
| change_policy.security_or_emergency_fix.CONSTRAINED | "" |
| change_policy.security_or_emergency_fix.EXHAUSTED | "" |
| change_policy.incident_mitigation_or_rollback.NORMAL | "" |
| change_policy.incident_mitigation_or_rollback.CONSTRAINED | "" |
| change_policy.incident_mitigation_or_rollback.EXHAUSTED | "" |
| reliability_work.activation_rule | "" |
| reliability_work.prioritization_rule | ["", ""] |
| reliability_work.required_outputs | [""] |
| reliability_work.owner | "" |
| reliability_work.exit_criteria | [""] |
| exception_policy.eligible_cases | [""] |
| exception_policy.requester | "" |
| exception_policy.required_evidence | [""] |
| exception_policy.approval_authority | "" |
| exception_policy.escalation_authority | "" |
| exception_policy.expiry_rule | "" |
| exception_policy.post_change_review | "" |
| exception_policy.audit_location | "" |
| ownership.service_or_product_owner | "" |
| ownership.slo_owner | "" |
| ownership.change_policy_owner | "" |
| ownership.reliability_work_owner | "" |
| ownership.exception_approver | "" |
| ownership.escalation_owner | "" |
| review.regular_cadence | "" |
| review.event_driven_triggers[0] | user_journey_changed |
| review.event_driven_triggers[1] | sli_definition_changed |
| review.event_driven_triggers[2] | measurement_coverage_changed |
| review.event_driven_triggers[3] | dependency_changed |
| review.event_driven_triggers[4] | traffic_or_customer_mix_changed |
| review.event_driven_triggers[5] | repeated_policy_exception |
| review.event_driven_triggers[6] | material_slo_miss |
| review.event_driven_triggers[7] | user_feedback_conflicts_with_slo |
| review.review_questions[0] | Does this SLI still describe user reliability? |
| review.review_questions[1] | Does the target match actual user harm? |
| review.review_questions[2] | Is the window appropriate for operational and planning decisions? |
| review.review_questions[3] | Does budget state change real work priorities? |
| review.review_questions[4] | Was the distinction between restricted and permitted changes appropriate? |
| review.review_questions[5] | Are exceptions used more often than the normal path? |
| review.review_questions[6] | Does applying the policy create excessive toil or excessive risk? |
Split measure, decide, and execute into three documents
Trying to solve reliability operations in one document blurs the boundaries. The earlier indicator design stage builds SLIs from user journeys and hands the target, window, error budget, and deployment policy to the next stage. This article takes that input and decides the target, window, error budget, budget consumption, policy state, release and change policy, reliability work, exceptions, and owners.
The next problems fork again. When budget burn should be told to a person is alerting design. Which of logs, metrics, traces, and profiles to look at first during an incident is signal selection. Detection, mitigation, recovery, and communication belong to the incident runbook. And the architecture that safely performs a pause, a rollback, or a traffic drain when the policy calls for one is a rollback design question.
Whether SLOs and error budgets became a real measure cannot be judged by counting dashboards. When the budget falls, the team's behaviour has to change, that behaviour has to have been agreed in advance, changes that reduce risk have to be told apart from changes that add it, and exceptions and responsibility have to be recorded. If the budget changes no decision, the SLO is closer to a reporting number. If a shrinking budget blocks every change equally, the policy is far too coarse. The real operating measure sits in between: connecting the reliability promised to users, the error budget remaining, the risk a change adds, and the person accountable for that decision into one policy.



