Modern QA2026Multi-Metric Quality Gates — tiles
Log inJoin
17 / 67 · 06 Observability-Driven Testing · A/B Tests as Quality Gates← prev⊞ allnext →☰ Read as one page

3.4Multi-Metric Quality Gates

Real-world quality gates evaluate multiple metrics simultaneously:

# multi_metric_quality_gate.py
from dataclasses import dataclass
from enum import Enum

class GateResult(Enum):
    PASS = "pass"
    WARN = "warn"
    FAIL = "fail"

@dataclass
class MetricGate:
    name: str
    metric_type: str           # "lower_is_better" or "higher_is_better"
    critical: bool             # if True, failure blocks deployment
    max_degradation_pct: float # maximum allowed degradation (e.g., 0.10 = 10%)

def evaluate_quality_gates(
    control_metrics: dict,
    canary_metrics: dict,
    gates: list[MetricGate]
) -> dict:
    """Evaluate all quality gates and produce a deployment decision."""
    results = []
    any_critical_fail = False

    for gate in gates:
        control_val = control_metrics[gate.name]
        canary_val = canary_metrics[gate.name]

        if gate.metric_type == "lower_is_better":
            # e.g., error rate, latency -- canary should not be higher
            degradation = (canary_val - control_val) / control_val if control_val > 0 else 0
            passed = degradation < gate.max_degradation_pct
        else:
            # e.g., throughput, conversion -- canary should not be lower
            degradation = (control_val - canary_val) / control_val if control_val > 0 else 0
            passed = degradation < gate.max_degradation_pct

        result = GateResult.PASS if passed else (GateResult.FAIL if gate.critical else GateResult.WARN)

        if result == GateResult.FAIL and gate.critical:
            any_critical_fail = True

        results.append({
            "gate": gate.name,
            "control": control_val,
            "canary": canary_val,
            "degradation": f"{degradation:.2%}",
            "threshold": f"{gate.max_degradation_pct:.0%}",
            "result": result.value,
            "critical": gate.critical,
        })

    return {
        "decision": "ROLLBACK" if any_critical_fail else "PROMOTE",
        "gates": results,
    }


# Define quality gates
gates = [
    MetricGate("error_rate", "lower_is_better", critical=True, max_degradation_pct=0.50),
    MetricGate("p99_latency_ms", "lower_is_better", critical=True, max_degradation_pct=0.25),
    MetricGate("p50_latency_ms", "lower_is_better", critical=False, max_degradation_pct=0.15),
    MetricGate("conversion_rate", "higher_is_better", critical=False, max_degradation_pct=0.05),
    MetricGate("cpu_usage_pct", "lower_is_better", critical=False, max_degradation_pct=0.30),
]

# Example metrics
result = evaluate_quality_gates(
    control_metrics={"error_rate": 0.02, "p99_latency_ms": 450, "p50_latency_ms": 120,
                     "conversion_rate": 0.034, "cpu_usage_pct": 55},
    canary_metrics={"error_rate": 0.021, "p99_latency_ms": 480, "p50_latency_ms": 125,
                    "conversion_rate": 0.033, "cpu_usage_pct": 58},
    gates=gates,
)
print(f"Decision: {result['decision']}")
for g in result['gates']:
    print(f"  {g['gate']}: {g['result']} (degradation: {g['degradation']})")