"""Refusals in the rule's own words. The application maps them: RuleBroken 409, Incomplete / Invalid 422,
NotFound 404 (also for a row the caller may not see — never 403)."""
class RuleBroken(Exception):
"""A business rule says no (409): 'version 2 is out for signature; recall it to edit'."""
class Invalid(ValueError):
"""The input itself is wrong (422): a date that is not a date, an enum value that is not one."""
class Incomplete(Exception):
"""Something required is missing (422). `missing` names each field so a caller can fill them."""
def __init__(self, message: str, missing: list = ()):
super().__init__(message)
self.missing = list(missing)
class NotFound(Exception):
"""No such thing — or one the caller may not see (404)."""