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
//! # Cycle Time and Its Components
//!
//! Cycle time is the internal breakdown of a change's flow time (see
//! [`crate::flow_framework`]) into its constituent engineering stages:
//! coding, pickup (waiting for a reviewer to start), review, test, and
//! deploy. Where flow time gives a single end-to-end number, cycle time
//! tells you where that time actually goes once work reaches engineering —
//! the diagnostic layer underneath the summary number.
//!
//! ## Formula
//!
//! ```text
//! Cycle time = coding + pickup + review + test + deploy
//!
//! coding = first commit → pull request opened
//! pickup = pull request opened → first review
//! review = first review → approval
//! test = time spent in automated/manual verification
//! deploy = approval → production
//! ```
//!
//! ## Why it matters
//!
//! "Lead time is too long" is not actionable on its own. A team whose lead
//! time is dominated by coding time needs a different intervention than a
//! team whose lead time is dominated by a three-day review queue, which
//! needs a different intervention again than a team losing most of its time
//! to a flaky, slow test suite. Without cycle-time decomposition, teams
//! guess at the bottleneck, and the guess is wrong often enough that fixing
//! the wrong stage wastes real effort while the actual constraint stays
//! untouched. Decomposition by stage also reveals shared, cross-team
//! bottlenecks — for example a single overloaded shared review pool — that
//! no individual team's own metrics can see on their own.
//!
//! ## Example
//!
//! A change with 2 days of coding, 0.5 days waiting for pickup, 1.5 days in
//! review, 0.5 days in test, and 0.5 days to deploy has a cycle time of 5
//! days; review is 30% of the total, the largest single share.
//!
//! ```rust
//! use software_engineering::cycle_time::{cycle_time, stage_percent_of_cycle};
//!
//! let total = cycle_time(2.0, 0.5, 1.5, 0.5, 0.5);
//! assert_eq!(total, 5.0);
//!
//! let review_share = stage_percent_of_cycle(1.5, total).unwrap();
//! assert!((review_share - 30.0).abs() < 1e-9);
//! ```
//!
//! ## Pitfalls
//!
//! - **Reacting to a lead-time regression without cycle-time diagnosis**:
//! frequently leads to fixing the wrong stage.
//! - **Assuming active effort, not wait time, is the dominant cost**:
//! usually wrong — queueing dominates in most real delivery pipelines (see
//! [`crate::flow_framework::flow_efficiency_percent`]).
//! - **Missing a shared, cross-team bottleneck** by reviewing cycle time
//! team by team only, rather than aggregating across teams.
//! - **Stage-boundary definitional drift**: marking a stage "started" or
//! "finished" earlier or later than its documented definition flatters a
//! number without real improvement. Audit stage-boundary instrumentation
//! periodically against its documented definition.
//!
//! ## Sources
//!
//! - Chapter 2.6, "Cycle time and its components."
//!
//! Topic doc: software-engineering-metrics/locales/en-001/chapters/02-06-cycle-time-and-its-components.md
/// Cycle time: the sum of a change's five named engineering stages.
///
/// # Arguments
///
/// * `coding` — first commit to pull request opened.
/// * `pickup` — pull request opened to first review.
/// * `review` — first review to approval.
/// * `test` — time spent in automated/manual verification.
/// * `deploy` — approval to production.
///
/// # Returns
///
/// The total cycle time, in whatever unit the stage durations are expressed.
///
/// # Examples
///
/// ```rust
/// use software_engineering::cycle_time::cycle_time;
///
/// let total = cycle_time(2.0, 0.5, 1.5, 0.5, 0.5);
/// assert_eq!(total, 5.0);
/// ```
/// A single stage's share of total cycle time, as a percentage.
///
/// Use this to set stage-specific improvement targets ("reduce median review
/// wait time from two days to four hours") rather than a vague overall
/// "reduce lead time by 20%" goal that gives a team no guidance on where to
/// focus.
///
/// # Arguments
///
/// * `stage_duration` — the duration of one stage.
/// * `total_cycle_time` — the total cycle time across all stages.
///
/// # Returns
///
/// `Some(percentage)` (e.g. `30.0` for 30%), or `None` when
/// `total_cycle_time` is zero.
///
/// # Examples
///
/// ```rust
/// use software_engineering::cycle_time::stage_percent_of_cycle;
///
/// let review_share = stage_percent_of_cycle(1.5, 5.0).unwrap();
/// assert!((review_share - 30.0).abs() < 1e-9);
/// assert_eq!(stage_percent_of_cycle(1.5, 0.0), None);
/// ```