Given baseline and canary metrics, return whether to continue,
pause, or roll back. Critical regressions should override wins.
Hidden answer: invariant, tests, and Python solution
Invariant: every metric is compared in the direction that matters
for the product. Test quality regression with latency win, latency
regression with quality win, missing metrics, invalid budget
definitions, and exactly-on-budget changes.
def canary_decision(baseline, canary, budgets):
actions = []
for name, budget in budgets.items():
required_fields = {"direction", "allowed_delta"}
missing_fields = required_fields - budget.keys()
if missing_fields:
missing = ", ".join(sorted(missing_fields))
raise ValueError(f"budget for {name} missing: {missing}")
if name not in baseline or name not in canary:
actions.append(("pause", name, "missing metric"))
continue
direction = budget["direction"]
allowed = budget["allowed_delta"]
if allowed < 0:
raise ValueError("allowed_delta must be non-negative")
delta = canary[name] - baseline[name]
tolerance = 1e-12
if direction == "lower_is_better" and delta - allowed > tolerance:
actions.append(("rollback", name, delta))
elif direction == "higher_is_better" and -delta - allowed > tolerance:
actions.append(("rollback", name, delta))
elif direction not in {"lower_is_better", "higher_is_better"}:
raise ValueError(f"unknown direction for {name}: {direction}")
if any(action[0] == "rollback" for action in actions):
return "rollback", actions
if actions:
return "pause", actions
return "continue", []