Skip to main content

domain/daycare/
incident.rs

1//! Daycare incident disposition rules that preserve pet-safety review gates.
2//!
3//! ```
4//! use domain::{daycare, entities, policy};
5//! use uuid::Uuid;
6//!
7//! let pet_id = entities::PetId(Uuid::nil());
8//! let disposition = daycare::incident::Classifier
9//!     .classify(pet_id, daycare::incident::Severity::SuspendGroupPlay);
10//!
11//! assert_eq!(disposition.required_gate(), Some(policy::ReviewGate::ManagerApproval));
12//! assert_eq!(
13//!     disposition.restriction(),
14//!     daycare::incident::Restriction::SuspendedPendingManagerReview { pet_id },
15//! );
16//! ```
17
18use super::*;
19use crate::{entities, policy};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22/// Daycare incident handling policy that determines notes, customer notice, and group-play suspension.
23pub enum Policy {
24    /// Incident is recorded as a staff note without extra customer or manager workflow.
25    StaffNoteOnly,
26    /// Incident requires manager review and customer-message approval before follow-up.
27    ManagerReviewAndCustomerNotice,
28    /// Incident should suspend group play until manager review clears the pet.
29    SuspendGroupPlayPendingReview,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33/// Severity classification supplied to the incident classifier.
34pub enum Severity {
35    /// Incident is recorded as a staff note without extra customer or manager workflow.
36    StaffNoteOnly,
37    /// Incident requires customer notice but does not itself suspend group play.
38    OwnerNotice,
39    /// Incident requires manager review before staff close the disposition.
40    ManagerReview,
41    /// Incident should suspend group play pending manager review.
42    SuspendGroupPlay,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46/// Operational restriction created by a daycare incident disposition.
47pub enum Restriction {
48    /// Incident creates no active restriction on future daycare attendance.
49    None,
50    /// Pet whose group-play access is suspended pending manager review.
51    SuspendedPendingManagerReview {
52        /// Pet id carried by this variant.
53        pet_id: PetId,
54    },
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
58/// Classified incident outcome carrying restriction and review-gate evidence.
59pub struct Disposition {
60    /// Pet whose group-play access is suspended pending manager review.
61    pub pet_id: PetId,
62    /// Severity used to choose restriction and review gates.
63    pub severity: Severity,
64    restriction: Restriction,
65    required_gate: Option<policy::ReviewGate>,
66}
67
68impl Disposition {
69    /// Returns the operational restriction that eligibility policy must honor.
70    pub const fn restriction(&self) -> Restriction {
71        self.restriction
72    }
73
74    /// Returns the human review gate required before the incident disposition can be cleared.
75    pub fn required_gate(&self) -> Option<policy::ReviewGate> {
76        self.required_gate.clone()
77    }
78}
79
80#[derive(Debug, Clone, Default)]
81/// Deterministic classifier that maps incident severity to restrictions and review gates.
82pub struct Classifier;
83
84impl Classifier {
85    /// Classifies an incident severity for a pet into a disposition staff can act on.
86    pub fn classify(&self, pet_id: entities::PetId, severity: Severity) -> Disposition {
87        let (restriction, required_gate) = match severity {
88            Severity::StaffNoteOnly => (Restriction::None, None),
89            Severity::OwnerNotice => (
90                Restriction::None,
91                Some(policy::ReviewGate::CustomerMessageApproval),
92            ),
93            Severity::ManagerReview => {
94                (Restriction::None, Some(policy::ReviewGate::ManagerApproval))
95            }
96            Severity::SuspendGroupPlay => (
97                Restriction::SuspendedPendingManagerReview { pet_id },
98                Some(policy::ReviewGate::ManagerApproval),
99            ),
100        };
101        Disposition {
102            pet_id,
103            severity,
104            restriction,
105            required_gate,
106        }
107    }
108}