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}