1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//! # Escaped Defect Rate and Quality Escapes
//!
//! An **escaped defect** is one that reaches production rather than being
//! caught before release. The escaped defect rate compares how many defects
//! escaped against how many were found in total (pre- and post-release
//! combined), giving a direct read on how well internal quality practices
//! are catching problems before customers do. A raw count understates the
//! picture: weighting by severity, using a consistent, documented scale,
//! stops a spike in minor issues from visually swamping a smaller but far
//! more consequential rise in critical ones.
//!
//! ## Formula
//!
//! ```text
//! Escaped defect rate (%) = escaped defects / (escaped defects + caught defects) × 100
//! Severity-weighted score = critical × 5 + major × 3 + minor × 1
//! ```
//!
//! ## Why it matters
//!
//! Classifying every escaped defect on a fixed severity scale, based on
//! actual customer or business impact, and tracking a severity-weighted
//! trend rather than just a raw count, is what keeps a handful of critical
//! escapes from being buried under a much larger count of cosmetic ones.
//! Standardizing classification criteria across teams matters just as much:
//! left to classify independently, teams drift toward different standards,
//! making cross-team comparison meaningless and creating an incentive to
//! classify generously downward to flatter a team's own numbers.
//!
//! ## Example
//!
//! ```rust
//! use software_engineering::escaped_defects::{
//! escaped_defect_rate_percent, severity_weighted_escaped_defect_score,
//! };
//!
//! // 4 defects escaped to production out of 40 found in total.
//! let rate = escaped_defect_rate_percent(4.0, 36.0).unwrap();
//! assert_eq!(rate, 10.0);
//!
//! // 1 critical escape outweighs 4 minor ones under severity weighting.
//! let one_critical = severity_weighted_escaped_defect_score(1.0, 0.0, 0.0);
//! let four_minor = severity_weighted_escaped_defect_score(0.0, 0.0, 4.0);
//! assert!(one_critical > four_minor);
//! // But 10 minors already outweigh a single critical.
//! let ten_minor = severity_weighted_escaped_defect_score(0.0, 0.0, 10.0);
//! assert!(ten_minor > one_critical);
//! // And 3 criticals outweigh those same 10 minors.
//! let three_critical = severity_weighted_escaped_defect_score(3.0, 0.0, 0.0);
//! assert!(three_critical > ten_minor);
//! ```
//!
//! ## Pitfalls
//!
//! - **Tracking a raw escaped-defect count** instead of a severity-weighted
//! trend — lets a spike in minor issues visually swamp a smaller, more
//! consequential rise in critical ones.
//! - **Letting teams classify severity independently**, without a
//! documented, audited scale — produces cross-team comparisons that are
//! meaningless at best and gamed at worst.
//! - **Tracking count and severity without root cause** — misses the
//! systemic pattern (a testing gap, a missed edge case, an
//! environment difference) that would point at a specific, fixable
//! process gap.
//! - **Framing defect classification as an individual-blame exercise** —
//! creates a strong incentive to under-report or misclassify downward.
//!
//! ## Sources
//!
//! - Chapter 5.1, Escaped defect rate and quality escapes.
//!
//! Topic doc: software-engineering-metrics/locales/en-001/chapters/05-01-escaped-defect-rate-and-quality-escapes.md
/// Weight applied to a critical-severity escaped defect in
/// [`severity_weighted_escaped_defect_score`].
///
/// A common, documented convention, not a universal constant — teams should
/// adapt the scale to their own context, per the chapter's "consistent,
/// documented scale" guidance.
pub const CRITICAL_WEIGHT: f64 = 5.0;
/// Weight applied to a major-severity escaped defect in
/// [`severity_weighted_escaped_defect_score`]. See [`CRITICAL_WEIGHT`].
pub const MAJOR_WEIGHT: f64 = 3.0;
/// Weight applied to a minor-severity escaped defect in
/// [`severity_weighted_escaped_defect_score`]. See [`CRITICAL_WEIGHT`].
pub const MINOR_WEIGHT: f64 = 1.0;
/// Escaped defect rate: the percentage of all found defects that escaped to
/// production rather than being caught first.
///
/// `escaped_defects / (escaped_defects + caught_defects) × 100`.
///
/// # Arguments
///
/// * `escaped_defects` — count of defects found in production.
/// * `caught_defects` — count of defects found before release.
///
/// # Returns
///
/// The escaped defect rate as a percentage, or `None` if both counts are
/// zero.
///
/// # Examples
///
/// ```rust
/// use software_engineering::escaped_defects::escaped_defect_rate_percent;
///
/// assert_eq!(escaped_defect_rate_percent(4.0, 36.0), Some(10.0));
/// assert_eq!(escaped_defect_rate_percent(0.0, 0.0), None);
/// ```
/// A severity-weighted escaped-defect score, so a spike in minor issues
/// cannot visually swamp a smaller rise in critical ones.
///
/// `critical × `[`CRITICAL_WEIGHT`]` + major × `[`MAJOR_WEIGHT`]` + minor ×
/// `[`MINOR_WEIGHT`].
///
/// # Arguments
///
/// * `critical` — count of critical-severity escaped defects.
/// * `major` — count of major-severity escaped defects.
/// * `minor` — count of minor-severity escaped defects.
///
/// # Returns
///
/// The severity-weighted score.
///
/// # Examples
///
/// ```rust
/// use software_engineering::escaped_defects::severity_weighted_escaped_defect_score;
///
/// // A single critical escape outweighs 4 minor ones.
/// let critical = severity_weighted_escaped_defect_score(1.0, 0.0, 0.0);
/// let minors = severity_weighted_escaped_defect_score(0.0, 0.0, 4.0);
/// assert!(critical > minors);
/// ```