173 lines
5.3 KiB
Python
173 lines
5.3 KiB
Python
"""Domain exceptions for repair workflows."""
|
|
|
|
|
|
class RepairError(Exception):
|
|
"""Base exception for repair operations."""
|
|
|
|
|
|
class RepairMinerNotFound(RepairError):
|
|
"""Raised when the requested miner does not exist."""
|
|
|
|
def __init__(self, miner_id: object):
|
|
self.miner_id = miner_id
|
|
super().__init__(f"Miner not found: {miner_id}")
|
|
|
|
|
|
class RepairNotFound(RepairError):
|
|
"""Raised when the requested repair does not exist."""
|
|
|
|
def __init__(self, repair_id: object):
|
|
self.repair_id = repair_id
|
|
super().__init__(f"Repair not found: {repair_id}")
|
|
|
|
|
|
class RepairConflict(RepairError):
|
|
"""Base exception for a conflicting repair state."""
|
|
|
|
|
|
class ActiveRepairConflict(RepairConflict):
|
|
"""Raised when a miner already has an active repair."""
|
|
|
|
def __init__(self, miner_id: object):
|
|
self.miner_id = miner_id
|
|
super().__init__(f"Miner already has an active repair: {miner_id}")
|
|
|
|
|
|
class IncompatibleMinerLifecycle(RepairConflict):
|
|
"""Raised when the miner lifecycle cannot enter repair."""
|
|
|
|
def __init__(self, miner_id: object, lifecycle_status: object):
|
|
self.miner_id = miner_id
|
|
self.lifecycle_status = lifecycle_status
|
|
super().__init__(
|
|
"Miner lifecycle is incompatible with beginning repair: "
|
|
f"{lifecycle_status}"
|
|
)
|
|
|
|
|
|
class InconsistentRepairState(RepairConflict):
|
|
"""Raised when lifecycle state and repair records disagree."""
|
|
|
|
def __init__(self, miner_id: object):
|
|
self.miner_id = miner_id
|
|
super().__init__(
|
|
"Miner is marked in repair but has no active repair record"
|
|
)
|
|
|
|
|
|
class RepairActorRequired(RepairError):
|
|
"""Raised when an operational workflow lacks an authenticated actor."""
|
|
|
|
def __init__(self):
|
|
super().__init__("An authenticated actor is required to begin repair")
|
|
|
|
|
|
class RepairCompletionActorRequired(RepairError):
|
|
"""Raised when Return to Service lacks an authenticated actor."""
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
"An authenticated actor is required to return a miner to service"
|
|
)
|
|
|
|
|
|
class RepairNotActive(RepairConflict):
|
|
"""Raised when a repair is no longer active."""
|
|
|
|
def __init__(self, repair_id: object, repair_status: object):
|
|
self.repair_id = repair_id
|
|
self.repair_status = repair_status
|
|
super().__init__(
|
|
f"Repair is not active: {repair_id} ({repair_status})"
|
|
)
|
|
|
|
|
|
class RepairMinerNotInRepair(RepairConflict):
|
|
"""Raised when a repair's miner has already left repair lifecycle."""
|
|
|
|
def __init__(self, miner_id: object, lifecycle_status: object):
|
|
self.miner_id = miner_id
|
|
self.lifecycle_status = lifecycle_status
|
|
super().__init__(
|
|
"Miner is not in repair lifecycle: "
|
|
f"{miner_id} ({lifecycle_status})"
|
|
)
|
|
|
|
|
|
class RepairActiveMismatch(RepairConflict):
|
|
"""Raised when the requested repair is not the miner's active repair."""
|
|
|
|
def __init__(self, repair_id: object, miner_id: object):
|
|
self.repair_id = repair_id
|
|
self.miner_id = miner_id
|
|
super().__init__(
|
|
f"Repair is not the active repair for miner: {repair_id}"
|
|
)
|
|
|
|
|
|
class RepairPersistenceError(RepairError):
|
|
"""Raised when a required repair persistence operation fails."""
|
|
|
|
|
|
class ControlBoardReplacementActorRequired(RepairError):
|
|
"""Raised when a board replacement lacks an authenticated actor."""
|
|
|
|
def __init__(self):
|
|
super().__init__("An authenticated actor is required to replace a control board")
|
|
|
|
|
|
class ControlBoardReplacementConflict(RepairConflict):
|
|
"""Raised when current repair, component, or MAC state blocks replacement."""
|
|
|
|
|
|
class InvalidMacAddress(RepairError):
|
|
"""Raised when a replacement MAC is malformed or prohibited."""
|
|
|
|
def __init__(self, message: str = "New MAC address is invalid"):
|
|
super().__init__(message)
|
|
|
|
|
|
class MacOwnershipConflict(ControlBoardReplacementConflict):
|
|
"""Raised when a MAC belongs to another durable miner."""
|
|
|
|
def __init__(self, normalized_mac: str):
|
|
self.normalized_mac = normalized_mac
|
|
super().__init__(
|
|
"MAC address has current or historical ownership on another miner"
|
|
)
|
|
|
|
|
|
class RepairPartNotFound(RepairError):
|
|
"""Raised when a nested repair-part UUID does not exist for a repair."""
|
|
|
|
def __init__(self, repair_part_id: object):
|
|
self.repair_part_id = repair_part_id
|
|
super().__init__(f"Repair part not found: {repair_part_id}")
|
|
|
|
|
|
class RepairPartComponentNotFound(RepairError):
|
|
"""Raised when a tracked component UUID does not exist."""
|
|
|
|
def __init__(self, component_id: object):
|
|
self.component_id = component_id
|
|
super().__init__(f"Component not found: {component_id}")
|
|
|
|
|
|
class RepairPartValidationError(RepairError):
|
|
"""Raised when repair-part input violates a domain rule."""
|
|
|
|
|
|
class RepairPartActorRequired(RepairError):
|
|
"""Raised when a repair-part action lacks an authenticated actor."""
|
|
|
|
def __init__(self):
|
|
super().__init__("An authenticated actor is required for repair-part actions")
|
|
|
|
|
|
class RepairPartAlreadyVoided(RepairConflict):
|
|
"""Raised when an immutable repair-part entry was already voided."""
|
|
|
|
def __init__(self, repair_part_id: object):
|
|
self.repair_part_id = repair_part_id
|
|
super().__init__(f"Repair part is already voided: {repair_part_id}")
|