Skip to main content

domain/daycare/
coverage.rs

1//! Daycare staff-coverage policy for group-play ratio review.
2//!
3//! ```
4//! use domain::{daycare, policy};
5//!
6//! let roster = daycare::coverage::RosterSnapshot::new(
7//!     daycare::StaffCount::try_new(1).unwrap(),
8//!     daycare::PetCount::try_new(18).unwrap(),
9//! );
10//! let allowed_ratio = daycare::StaffPetRatio::new(
11//!     daycare::StaffCount::try_new(1).unwrap(),
12//!     daycare::PetCount::try_new(12).unwrap(),
13//! );
14//!
15//! assert_eq!(
16//!     daycare::coverage::Policy.evaluate(&roster, allowed_ratio),
17//!     daycare::coverage::Decision::Insufficient {
18//!         reason: daycare::coverage::InsufficiencyReason::RatioExceeded,
19//!         gate: policy::ReviewGate::ManagerApproval,
20//!     },
21//! );
22//! ```
23
24use super::*;
25use crate::policy;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
28/// Point-in-time daycare roster evidence for staffing-ratio decisions.
29pub struct RosterSnapshot {
30    scheduled_staff: StaffCount,
31    checked_in_pets: PetCount,
32}
33
34impl RosterSnapshot {
35    /// Creates a roster snapshot from scheduled staff and checked-in pet counts.
36    pub const fn new(scheduled_staff: StaffCount, checked_in_pets: PetCount) -> Self {
37        Self {
38            scheduled_staff,
39            checked_in_pets,
40        }
41    }
42
43    /// Returns scheduled staff available to supervise daycare pets.
44    pub const fn scheduled_staff(&self) -> StaffCount {
45        self.scheduled_staff
46    }
47
48    /// Returns pets already checked in and counted against the staffing ratio.
49    pub const fn checked_in_pets(&self) -> PetCount {
50        self.checked_in_pets
51    }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55/// Staffing coverage decision used by eligibility, assignment, and front-desk routing.
56pub enum Decision {
57    /// Scheduled staff can cover the checked-in pet count under the configured ratio.
58    Sufficient,
59    /// Checked-in pet count exceeds allowed coverage and needs manager review.
60    Insufficient {
61        /// Reason staffing coverage is insufficient.
62        reason: InsufficiencyReason,
63        /// Human review gate required before staff override coverage policy.
64        gate: policy::ReviewGate,
65    },
66    /// Coverage evidence is unavailable or uncertain, so staff review is required.
67    Unknown {
68        /// Human review gate required before staff override coverage policy.
69        gate: policy::ReviewGate,
70    },
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
74/// Reasons daycare staffing coverage is insufficient.
75pub enum InsufficiencyReason {
76    /// Pet count exceeds the allowed pets-per-staff ratio.
77    RatioExceeded,
78}
79
80#[derive(Debug, Clone, Default)]
81/// Deterministic staffing-coverage policy for daycare ratio review.
82pub struct Policy;
83
84impl Policy {
85    /// Evaluates scheduled staff and checked-in pets against the allowed ratio.
86    pub fn evaluate(&self, roster: &RosterSnapshot, ratio: StaffPetRatio) -> Decision {
87        let allowed = roster
88            .scheduled_staff()
89            .get()
90            .saturating_mul(ratio.pets_per_staff().get());
91        if roster.checked_in_pets().get() <= allowed {
92            Decision::Sufficient
93        } else {
94            Decision::Insufficient {
95                reason: InsufficiencyReason::RatioExceeded,
96                gate: policy::ReviewGate::ManagerApproval,
97            }
98        }
99    }
100}