cadrumo.core.errors.hierarchy module

The Cadrumo exception hierarchy, and the site-health shapes beside it.

Every refusal in the application descends from CadrumoError, so this module is the root of the error tree rather than a collection of unrelated classes. It deliberately imports nothing from the error-code registry: the registry knows about the hierarchy, not the other way round, and keeping the arrow pointing one way is what lets cadrumo.core.json_contract depend on the hierarchy without dragging the registry in behind it.

Keeping these classes in their own defining module lets cadrumo.core.json_contract depend on the hierarchy without loading registry-owned envelope models.

class SiteHealthState(*values)[source]

Bases: StrEnum

Closed catalogue of layer-neutral AEAT site-health classifications.

OK
MANTENIMIENTO
WAF_CHALLENGE
RATE_LIMITED
UNREACHABLE
UNKNOWN_ERROR
class SiteHealthEvidenceLike(*args, **kwargs)[source]

Bases: Protocol

Structural view of the evidence block carried by a site-health status.

Declared in core.errors so SiteHealthError can type its payload without importing the adapter layer that produces it. The concrete record is adapters.outbound.aeat.browser.site_health_records.SiteHealthEvidence.

Members are read-only properties so the protocol matches covariantly: a concrete record may carry narrower member types (e.g. AnyHttpUrl for url) and still satisfy the structural view, which a mutable attribute declaration would reject.

property url: object

URL that was probed during the health check.

property http_status: int

HTTP status code returned by the probed URL.

property detected_markers: Sequence[str]

Sequence of markers detected in the response that triggered classification.

class SiteHealthStatusLike(*args, **kwargs)[source]

Bases: Protocol

Structural view of a detected AEAT site-health classification.

Declared in core.errors so SiteHealthError can accept the status without a runtime or type-checking import of the adapter layer. The concrete record is adapters.outbound.aeat.browser.site_health_records.SiteHealthStatus.

Members are read-only properties so the protocol matches covariantly: the concrete SiteHealthStatus carries a concrete SiteHealthEvidence for evidence, which satisfies the SiteHealthEvidenceLike view only when the member is read-only.

property state: SiteHealthState

Classified site-health state (e.g. mantenimiento, WAF challenge, rate limit).

property evidence: SiteHealthEvidenceLike

Evidence block used to classify the detected state.

Returns a SiteHealthEvidenceLike carrying the URL, HTTP status, and detected markers that drove classification.

property observed_at: datetime

Timestamp at which the health check observation was recorded.

property retry_after_seconds: int | None

Suggested retry delay in seconds, or None when not provided.

exception CadrumoError(message=None, *, context=None, translated_message=None)[source]

Bases: Exception

Base exception for all registered Cadrumo errors.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code

Resolve a subclass’s declared code on first access.

Subclasses created before the declared-code catalogue loads are bound lazily; binding stores the code on the subclass itself, which then shadows this descriptor.

pydantic_validation_boundary(function)[source]

Translate registered failures for Pydantic’s validator protocol.

Pydantic turns ValueError and TypeError raised by validators into structured ValidationError instances, but it lets arbitrary exception classes escape. Cadrumo validation failures stay registered internally; this small decorator is applied only to validator callbacks that cross that protocol boundary and preserves the registered failure as __cause__ of the required builtin ValueError.

Return type:

Callable[[ParamSpec(PydanticArgs)], TypeVar(PydanticResultT)]

Parameters:

function (Callable[[PydanticArgs], PydanticResultT])

exception AuthError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Base class for every AEAT authentication boundary failure.

Parameters:
Return type:

None

code
exception AeatLoginAssertionError(message=None, *, context=None, translated_message=None)[source]

Bases: AuthError

Raised when an AEAT login assertion cannot be produced or trusted.

Parameters:
Return type:

None

code
class TerminalPreconditionErrorMixin(message=None, *, context=None, translated_message=None, precondition_verdict=None)[source]

Bases: Generic

Carry one typed terminal verdict without coupling core to application models.

The mixin deliberately stores the verdict as an opaque object: the application owns the concrete PreconditionVerdict record, while core owns this layer-neutral exception transport behavior. It is mixed in ahead of a registered error class so that class keeps its own error code.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

  • precondition_verdict (VerdictT | None)

property terminal_precondition_verdict: VerdictT | None

Return the opaque terminal verdict for the owning application boundary.

exception CoreError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Base error for internal framework and core-primitive failures.

Parameters:
Return type:

None

code
exception InternalInvariantError(message=None, *, context=None, translated_message=None)[source]

Bases: CoreError

Raised when composed production state violates an internal invariant.

Parameters:
Return type:

None

code
exception DecimalFormatError(message=None, *, context=None, translated_message=None)[source]

Bases: CoreError

Raised when core.decimal.formatting.format_decimal() receives an invalid argument.

Replaces the bare TypeError previously raised when value is None but none_value was not provided.

Parameters:
Return type:

None

code
exception RedactionError(message=None, *, context=None, translated_message=None)[source]

Bases: CoreError

Raised when a redaction helper receives an argument of the wrong type.

Replaces bare TypeError previously raised by core.redaction.rules.redact() and core.redaction.rules.redact_for_cli_output() when passed a non-str argument.

Parameters:
Return type:

None

code
exception CoreValidationError(message=None, *, context=None, translated_message=None)[source]

Bases: CoreError

Raised when core primitives or configuration violate invariants.

Pydantic validators translate this registered failure to ValueError at their narrow protocol boundary.

Parameters:
Return type:

None

code
exception ProfileAnswerTypeError(message=None, *, context=None, translated_message=None)[source]

Bases: CoreValidationError

Raised when a typed profile-answers field coercion receives an unexpected type.

Lives in core.errors so cadrumo.domain.user_profile.setup_answers.SetupAnswers can raise a typed error without importing application-layer wizard modules. Application-layer wizard code raises the narrower application.wizard.errors.WizardAnswerTypeError, which inherits from this class, so callers catching either type continue to work.

Parameters:
Return type:

None

code
exception CadrumoObservabilityError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Base class for observability-layer errors.

Lives in core.errors (rather than the leaf core.observability subpackage) so other subpackages can catch it without importing observability internals. Concrete subclasses are declared in core.observability.errors.

Parameters:
Return type:

None

code
exception SiteHealthError(*, status)[source]

Bases: CadrumoError

Raised when AEAT site-health detection classifies a non-OK state.

Carries a SiteHealthStatusLike payload describing the detected state (mantenimiento, WAF challenge, rate limit, unreachable, unknown error) together with the evidence used to classify it. The workflow engine catches this error in a typed arm that precedes the generic exception handler so a planned mantenimiento never collapses into UNHANDLED_EXCEPTION.

The error lives in core.errors (and not in either leaf subpackage) to break the circular import between adapters.outbound.aeat.browser (which raises it) and application.workflow (which consumes it). The payload is typed through the SiteHealthStatusLike structural Protocol declared in this module, so no import of the adapter layer occurs at runtime or under type checking — the core-not-outer boundary is satisfied without an exclusion.

Parameters:

status (SiteHealthStatusLike)

Return type:

None

code
exception ActiveProfilePointerError(*, path)[source]

Bases: CoreError

Raised when the active-profile pointer is present but invalid.

A missing pointer is a clean cold-start state. A present pointer that cannot be parsed, decoded, read, or validated is storage metadata corruption and does not resolve to a root fallback database route.

Parameters:

path (object)

Return type:

None

code
exception NoActiveProfileError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Raised when an operation requires an active profile bucket and none is selected.

Bucket-scoped repositories (transaction catalogue, manual ledger, bucket-local aggregation) and the operator-initiated auth/sede flows refuse to operate without an active profile. The active-bucket precedence chain is a core concern (env var > pointer file), so the refusal that gates it lives in the core error taxonomy and is raised by core.bucket_pointer.require_active_bucket_id(). Callers that surface this to the operator map it to the standard cli.common.errors.no_active_profile message.

Parameters:
Return type:

None

code