cadrumo.domain.calculations.registry.errors module

Registry error types for AEAT legal calculation definitions.

This module provides classmethod factories on RegistryValidationError and RegistrySnapshotError for each canonical raise scenario. The factory pattern pins the context-dict keys downstream consumers (cadrumo.core.errors.error_codes template renderer, CLI JSON emit via SchemaEnvelope, i18n locales referencing keys by name) rely on.

The existing raise RegistryValidationError(message, context=...) shape stays valid for one-off scenarios that haven’t been promoted to canonical factories yet; migration is additive and non-breaking.

class RegistryFailureCondition(*values)[source]

Bases: StrEnum

Domain-owned failed-condition identities for registry refusals.

These names identify facts the registry can observe. They deliberately do not encode a command or an outcome: application policy decides whether a live surface has a canonical action, and the CLI resolves that action.

TAXPAYER_MODEL_DECLARED
MODELO_202_INCN_DECLARED
QUERY_FILING_YEAR_SCOPED
QUERY_CASILLA_DECLARED
SNAPSHOT_AUTHORITY_GRADE_SUFFICIENT
SNAPSHOT_EXPORT_LAYOUT_DECLARED
TREE_QUIESCENT
class RegistryFailureClassification(condition, facts)[source]

Bases: object

One registry-observed failed condition and its locale-neutral facts.

Parameters:
condition: RegistryFailureCondition
facts: Mapping[str, str | int | bool]
exception RegistryError(message=None, *, context=None, translated_message=None, registry_failure=None, precondition_verdict=None)[source]

Bases: TerminalPreconditionErrorMixin[object], CadrumoError

Base error retaining domain facts for a higher-layer action projection.

Parameters:
Return type:

None

property registry_failure: RegistryFailureClassification | None

Return the domain fact classification for an application to resolve.

code
exception RegistryLoadError(message=None, *, context=None, translated_message=None, registry_failure=None, precondition_verdict=None)[source]

Bases: RegistryError

Raised when registry files cannot be parsed into strict schema objects.

Parameters:
Return type:

None

code
exception AuthorityDescriptorUnavailableError(*, searched_path, authority_root_configured, translated_message, detail)[source]

Bases: RegistryError

Raised when no published authority descriptor resolves for this process.

The descriptor is the selector for the content-addressed SQLite generation every registry read follows, so its absence is not a degraded mode: nothing downstream can be answered, and a caller that received an empty or partial authority instead of a refusal would publish an under-declared filing figure. Both arms therefore fail closed and name the location that was consulted.

Two arms exist because the remedies differ. An operator who set CADRUMO_AUTHORITY_ROOT pointed at a directory that holds no descriptor and needs to know which directory was read; an operator who set nothing is running against a distribution or checkout whose authority has never been published.

Structured attributes: searched_path, authority_root_configured.

Parameters:
  • searched_path (Path)

  • authority_root_configured (bool)

  • translated_message (str)

  • detail (str)

Return type:

None

classmethod for_configured_root(*, descriptor_path)[source]

cadrumo_authority_root names a directory carrying no descriptor.

Return type:

Self

Parameters:

descriptor_path (Path)

classmethod for_packaged_location(*, descriptor_path)[source]

No authority ships at the packaged location and no root was configured.

Return type:

Self

Parameters:

descriptor_path (Path)

code
exception RegistryValidationError(message=None, *, context=None, translated_message=None, registry_failure=None, precondition_verdict=None)[source]

Bases: RegistryError, CoreValidationError

Raised when registry definitions are incomplete or contradictory.

Its registered ancestry includes CoreValidationError under RegistryError, so callers use the canonical registry-bound catch surface. Pydantic validators translate this registered failure to ValueError at their narrow boundary.

Canonical raise scenarios route through one of the for_* classmethod factories so the context-dict keys consumed by locale templates and CLI JSON emit are pinned to a named contract per scenario.

Parameters:
Return type:

None

classmethod for_unknown_input_casilla_ids(*, casilla_ids)[source]

Inputs to the runtime referenced casilla ids absent from the revision.

Return type:

Self

Parameters:

casilla_ids (Sequence[CasillaId])

classmethod for_prorrata_activity_rows_incomplete(*, ejercicio)[source]

An applicable Modelo 303 ejercicio is missing a DP30305 activity row.

An absent row collection is honest only when the register’s regime says prorrata does not apply for ejercicio; once it applies, a partial collection must fail before a target export file can mask the under-declaration. Canonical key: shares the filing package’s pre-existing application.filing.m303_prorrata_activity_rows.errors. activity_rows_incomplete catalogue entry, which already carries the operator-facing sentence in all four locales.

Return type:

Self

Parameters:

ejercicio (int)

code
exception GovernedFactNotApplicableError(*, fact_id, effective_date, date_axis)[source]

Bases: RegistryValidationError

A registered governed fact authors no variant covering the query coordinate.

This is the governed-fact half of the invariant FilingYearOutsideSupportEnvelopeError holds for revision selection: absent and unresolvable are different states, and a caller that cannot tell them apart cannot choose a remedy.

Only this error means “the law authors nothing here”. Every other refusal the resolver raises – an unregistered fact id, a family mismatch, a coordinate the support envelope gates, an ambiguous variant set, a caller with no facts authority in scope at all – stays a plain RegistryValidationError, because each names a defect in the caller or the corpus rather than a statement about applicability.

The distinction is not academic. A compiler boundary that decides whether an observed source feature is legally expected resolves the fact and reads its absence as “not expected this year”. Catching the broad type there converts a missing scope, a mistyped fact id, or a corrupted payload into a confident claim about tax law – the silent under-declaration failure mode arriving from the opposite direction, where an unknown is promoted to a declared finding instead of demoted to zero.

Structured attributes: fact_id, effective_date, date_axis.

Parameters:
  • fact_id (str)

  • effective_date (date)

  • date_axis (str)

Return type:

None

code
exception RegistrySnapshotError(message=None, *, context=None, translated_message=None, registry_failure=None, precondition_verdict=None)[source]

Bases: RegistryError

Raised when a filing-grade snapshot cannot be selected.

The single canonical raise scenario is for_modelo_not_registered at the _authority.modelo boundary; the bare constructor stays valid for one-off scenarios not yet promoted to a factory.

Two temporal-selection scenarios carry structured context as dedicated subclasses (NoRevisionForPeriodError, AmbiguousRevisionSelectionError) so a consumer dispatches by except type rather than parsing the human-readable message. Both subclass this type, so every existing except RegistrySnapshotError site catches them unchanged.

Parameters:
Return type:

None

classmethod for_modelo_not_registered(*, modelo_id)[source]

The requested modelo id has no registered revision.

Return type:

Self

Parameters:

modelo_id (str)

code
exception NoRevisionForPeriodError(*, modelo_id, filing_year, period, revision_id, available_revision_ids)[source]

Bases: RegistrySnapshotError

No registry revision matches the requested temporal natural key.

Raised by select_revision() when the (modelo, filing year, period, optional date window, optional revision id) constraints select zero candidate revisions. Carries the natural-key components as structured context so a consumer (e.g. the config profile preflight resolver) can build an instructive refusal without parsing the message. Catchable as RegistrySnapshotError.

Structured attributes: modelo_id, filing_year, period, revision_id, available_revision_ids.

Parameters:
  • modelo_id (str)

  • filing_year (int)

  • period (str)

  • revision_id (RevisionId | None)

  • available_revision_ids (Iterable[str])

Return type:

None

code
exception EjercicioOrdenNotYetPublishedError(*, modelo_id, filing_year, period, revision_id, available_revision_ids, rests_on, expected_publication_year)[source]

Bases: NoRevisionForPeriodError

The modelo cannot answer this filing year yet, and says so itself.

An annual modelo is re-approved once per ejercicio, and the Orden approving ejercicio N is published during year N+1. A request for a year whose Orden is unwritten is not an oversight and not a gap anybody can close: no author can supply what the authority has not issued.

Raised in place of the plain absence refusal when the modelo declares a matching pending_ejercicio_ordenes entry. It subclasses NoRevisionForPeriodError deliberately – every existing handler keeps catching it, and the answer really is that no revision matched – so only callers that want the distinction pay any attention to it.

Structured attributes add rests_on and expected_publication_year to the inherited natural key, because an operator told to wait is owed both what the product currently rests on and when that changes.

Parameters:
  • modelo_id (str)

  • filing_year (int)

  • period (str)

  • revision_id (RevisionId | None)

  • available_revision_ids (Iterable[str])

  • rests_on (str)

  • expected_publication_year (int)

Return type:

None

code
exception FilingYearOutsideSupportEnvelopeError(*, modelo_id, filing_year, period, floor, horizon, hard_ceiling, covering_revision_ids)[source]

Bases: RegistrySnapshotError

The registry declines a coordinate its support envelope gates, not one it lacks.

A refused filing year has two unrelated causes, and conflating them costs triage time out of all proportion to the fix. Either no revision was ever authored for the coordinate – an authoring gap, answered by NoRevisionForPeriodError – or the corpus authors it perfectly well and the product’s declared filing envelope refuses to resolve it, which is a scope decision no amount of authoring changes. The second is this error.

Keeping them apart is the same invariant the sibling governed-fact resolver already holds: unsupported and absent are distinct states, and a consumer that cannot tell them apart cannot choose a remedy. The remedy differs completely – a gap is closed by authoring the revision, an out-of-envelope coordinate by resolving against the authority scoped to the authored history instead of the filing envelope, or by moving the envelope floor.

covering_revision_ids is deliberately the revisions whose own period selector DOES cover the requested coordinate. It is usually non-empty, and that is the whole point: the previous refusal reported those same ids under a message asserting nothing covered the year, so its own evidence contradicted its own claim.

Subclasses RegistrySnapshotError, not NoRevisionForPeriodError: every broad except RegistrySnapshotError site keeps catching it, while a handler that means “no revision was authored” no longer silently absorbs an envelope refusal.

Structured attributes: modelo_id, filing_year, period, floor, horizon, hard_ceiling, covering_revision_ids.

Parameters:
  • modelo_id (str)

  • filing_year (int)

  • period (str)

  • floor (int)

  • horizon (int)

  • hard_ceiling (int | None)

  • covering_revision_ids (Iterable[str])

Return type:

None

code
exception AmbiguousRevisionSelectionError(*, modelo_id, candidate_ids, filing_year=None, reason=None, translated_message='errors.snapshot.ambiguous_revision_selection')[source]

Bases: RegistrySnapshotError

More than one registry revision matches the temporal natural key.

Raised by select_revision() when the constraints select two or more candidate revisions. Carries the candidate revision ids as a structured, already-sorted tuple so a consumer can list them in an operator refusal without re-parsing the message. Catchable as RegistrySnapshotError.

THE REMEDY IS RAISER-SELECTED, through the locale key rather than through a second channel beside it. Two selectors raise this: the year-only one, where the fix is to supply a period or an as-of date, and the period-scoped one, where the caller has already supplied a period and that advice would send an operator to redo what they just did. No single string is correct for both, so the year-only raiser names its own translated_message and the period-scoped raiser keeps the shared default, which states the collision without prescribing an action the operator cannot take.

Structured attributes: modelo_id, candidate_ids, filing_year.

Parameters:
  • modelo_id (str)

  • candidate_ids (Iterable[str])

  • filing_year (int | None)

  • reason (str | None)

  • translated_message (str)

Return type:

None

code
exception CasillaConstraintViolationError(message=None, *, context=None, translated_message=None, registry_failure=None, precondition_verdict=None)[source]

Bases: RegistryError

Raised when a computed casilla value falls outside its declared constraints.

The constraint set is casilla.constraints (sign, min_value, max_value). The error envelope carries casilla_id, the offending value, the offended constraint clause, and the casilla’s legal_refs so the operator sees the BOE permalink that justifies the rule.

Parameters:
Return type:

None

code