pinto/service/sprint.rs
1//! Sprint creation, state transition, and PBI assignment services.
2//!
3//! Combines the [`crate::sprint::Sprint`] and [`crate::backlog::BacklogItem`] domain types with the
4//! persistence layer. A backlog item's sprint assignment is stored as the sprint ID string in
5//! `BacklogItem::sprint`. Split by concern into `lifecycle` (create/transition/assign) and
6//! `capacity` (capacity, load warnings, and listing).
7
8use crate::sprint::SprintId;
9
10mod capacity;
11mod lifecycle;
12
13pub use capacity::{list_sprints, set_sprint_capacity, sprint_capacity, sprint_load_warnings};
14pub(crate) use lifecycle::validate_sprint_assignment;
15pub use lifecycle::{
16 assign_sprint, assign_sprint_by_status, assign_sprint_raw, close_sprint, create_sprint,
17 delete_sprint, edit_sprint, start_sprint, unassign_sprint,
18};
19
20// Referenced by the test module below via `use super::*`.
21#[cfg(test)]
22use capacity::sprint_load_warnings_for;
23
24/// The source of a non-blocking Sprint load warning.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum SprintLoadWarningKind {
27 /// The assigned point total is above the configured capacity-hours threshold.
28 Capacity,
29 /// The assigned point total is above the historical velocity threshold.
30 Velocity,
31}
32
33impl SprintLoadWarningKind {
34 /// Return the short label used in localized CLI warning messages.
35 #[must_use]
36 pub const fn as_str(self) -> &'static str {
37 match self {
38 Self::Capacity => "capacity",
39 Self::Velocity => "velocity",
40 }
41 }
42
43 /// Return the unit attached to the numeric threshold in CLI output.
44 #[must_use]
45 pub const fn unit(self) -> &'static str {
46 match self {
47 Self::Capacity => "hours",
48 Self::Velocity => "points",
49 }
50 }
51}
52
53/// A non-blocking warning produced when a Sprint's assigned points exceed a threshold.
54#[derive(Debug, Clone, PartialEq)]
55pub struct SprintLoadWarning {
56 /// Which planning comparison was exceeded.
57 pub kind: SprintLoadWarningKind,
58 /// Sum of estimated points assigned to the Sprint.
59 pub points: u32,
60 /// Numeric threshold that the assigned points exceeded.
61 pub threshold: f64,
62}
63
64/// How unfinished PBIs are handled when their sprint closes.
65#[derive(Debug, Default, Clone, PartialEq, Eq)]
66pub enum SprintCloseAction {
67 /// Keep unfinished PBIs assigned to the closed sprint.
68 #[default]
69 Retain,
70 /// Reassign unfinished PBIs to a planned or active sprint.
71 Rollover(SprintId),
72 /// Clear the sprint assignment from unfinished PBIs.
73 Release,
74}
75
76#[cfg(test)]
77mod tests;