cadrumo.application.aggregation.source_mesh module

Canonical application-layer source resolution contracts.

The source mesh is the calculation-facing envelope for values derived from bucket-local ledgers, invoices, prior filings, profile facts, borrador data, relation prefill, and other registry-declared sources. A CalculationSourceContext binds the active bucket, modelo, Period, and selected ModeloRevision; each ModeloSourceResolver claims one or more BindingSourceKind members and returns a CalculationSourceResolution.

CalculationSourceResolution is the single resolved-source carrier consumed by modelo calculation. It carries decimal, enum, date, boolean, row-indexed binding, relation, bound-casilla, detail-row, transaction-id, diagnostic, and provenance channels. Exclusive merges use merge_source_resolutions(); precedence overlays use merge_source_resolutions_by_precedence(); and collect_unhandled_source_diagnostics() is the no-silent-blank safety net for declared binding sources without an enrolled resolver.

exception SourceMeshError(message_key)[source]

Bases: CoreValidationError

Raised when a CalculationSourceMesh field validator rejects an invariant.

Replaces bare ValueError at the owned_sources uniqueness / blank guards and the source_transaction_ids uniqueness / blank guards so callers receive a typed, registry-bound, localized error. Its canonical registered ancestry is CoreValidationError; pydantic field validators translate it to ValueError at their narrow boundary.

Parameters:

message_key (str)

Return type:

None

code
class CallerOverrideDisposition(*values)[source]

Bases: StrEnum

Whether the calculate path permits a caller override of a source’s value.

The override disposition axis of the caller-override precedence ladder.

Members:
LOCK: Deterministic bucket-owned resolvers (ledger aggregations,

invoice families, inventory projection, and other complete source authorities). A caller override is REJECTED so the persisted revision faithfully reflects the sources it aggregates.

CARRY: Carry-style sources (previous_filing, relation_prefill, the

IVA-compensation annual partition, and prorrata regularizacion). A caller override of an automatically-carried prior value is legitimate and must reach the engine, so these are EXCLUDED from the post-merge caller-override guard.

LOCK
CARRY
class CallerOverridePrecedenceTier(name, source_kinds, disposition)[source]

Bases: NamedTuple

One ordered tier of the calculate-path caller-override precedence ladder.

Carries the tier name, the source kinds it owns, and the override disposition the guard applies to them. The ordered ladder is the single declaration the caller-override guard sets are derived from — CALLER_OVERRIDE_PRECEDENCE_LADDER replaces the hand-listed lock / carry frozensets, and a conformance test binds the policy’s derived sets to it so the two cannot silently diverge.

Parameters:
name: str

Alias for field number 0

source_kinds: frozenset[BindingSourceKind]

Alias for field number 1

disposition: CallerOverrideDisposition

Alias for field number 2

CALLER_OVERRIDE_PRECEDENCE_LADDER: tuple[CallerOverridePrecedenceTier, ...]

The calculate-path caller-override precedence ladder as ordered tier data, lowest-precedence tier first. The guard’s lock and carry source sets are the unions of the LOCK- and CARRY-disposition tiers (see precedence_ladder_sources()). This encodes the override DISPOSITION axis only; the merge OVERLAY order (profile < mesh backend < borrador < caller, later tier wins) is enforced separately by merge_source_resolutions().

precedence_ladder_sources(disposition)[source]

Union of the source kinds carried by every ladder tier of disposition.

The single derivation the caller-override policy sets read, so a source kind’s lock-vs-carry disposition is declared once in CALLER_OVERRIDE_PRECEDENCE_LADDER rather than hand-listed per set.

Return type:

frozenset[BindingSourceKind]

Returns:

The BindingSourceKind members carried by every ladder tier whose disposition matches disposition.

Parameters:

disposition (CallerOverrideDisposition)

class CompositeSourceResolverId(*values)[source]

Bases: StrEnum

Closed identities owned only by source-resolution composition.

EXCLUSIVE_MESH
PRECEDENCE_MESH
class CalculationSourceContext(**data)[source]

Bases: BaseModel

Context supplied to a calculation source resolver.

The period field is the typed Period value carrying both the filing year and the bare registry period code. Consumers that need the raw token for a downstream str-typed API should use context.period.registry_token; those that need only the year can use context.period.filing_year (which mirrors context.filing_year).

profile is the profile the calculation loaded once for bucket_id. A resolver that needs profile facts reads them here rather than decrypting the record again; it is None only for contexts built outside a calculation command.

Parameters:

data (Any)

bucket_id: BucketId
work_unit_id: WorkUnitId | None
modelo: str
filing_year: FilingYear
period: Period
revision: ModeloRevision
m210_official_tipo_renta_code: str | None
m210_gross_income_source_mode: M210GrossIncomeSourceMode | None
calculated_at: datetime | None
profile: InstanceOf[ModeloWorkProfile] | None
DIAGNOSTIC_MESSAGE_MAX_LENGTH: Final[int]

Cap on a diagnostic’s operator-facing message.

DIAGNOSTIC_REMEDY_MAX_LENGTH: Final[int]

Cap on a diagnostic’s operator-facing remedy.

Bounded like every other string on this model, but bounded to REFUSE where message is bounded to elide, and the asymmetry is deliberate. A message interpolates the taxpayer’s own data, so its length is a property of the household and a filer with many descendants must never be the one whose advisory turns into a blocking error. A remedy is fixed prose naming a command: its length is a property of what the author typed, so an overrun is an authoring mistake that should surface loudly at authoring time rather than be silently cut in front of an operator. Any remedy that ever does interpolate taxpayer data must move to an eliding bound instead.

class CalculationSourceDiagnostic(**data)[source]

Bases: BaseModel

Diagnostic emitted while resolving source-backed calculation values.

Parameters:

data (Any)

reason: CalculationSourceDiagnosticReason
source_kind: str
binding_source: BindingSourceKind | None

Canonical binding source when source_kind names one; None for advisory categories.

message: _DiagnosticMessage
remedy: str | None

What the operator should DO about it, carried apart from what happened.

Separated because the two are read at different moments and bounded against different pressures. message states the problem and is the part whose length scales with taxpayer data – a household’s worth of interpolated descendant paths lands there – while the remedy is fixed prose naming a command. Fusing them made the fixed half compete for room against the variable half, so the filers with the most at stake were the ones whose remedy got cut.

Projected as the advisory’s operator remedy at the CLI boundary. None where the advisory discloses a state with no action attached to it.

resolver_id: str | None
source_ref: str | None
binding_id: BindingId | None
relation_id: RelationId | None
relation_ids: tuple[RelationId, ...]

Every relation this ONE diagnostic speaks for, when it groups several.

A diagnostic naming a missing source filing is about the FILING, not about any one relation reading it — Modelo 190’s ten annual-summary relations sourcing the same absent Modelo 111 return are ten symptoms of one cause, and reporting them as ten separate advisories trains an operator to stop reading the channel. relation_id stays populated with the lowest sorted member for a caller that only ever consulted the singular field before this one existed; this field is the FULL machine-readable set the grouped advisory actually covers. Empty for a diagnostic that was never about more than one relation to begin with — absence means “nothing to add beyond relation_id”, not “unknown”.

casilla_id: CasillaId | None
legal_refs: tuple[LegalRefId, ...]

Registry legal references grounding the subject this advisory speaks about.

Empty on an advisory whose subject is a mechanism rather than a regulated value – a degraded store, a duplicate owner – and populated by READING the grounding off the registry definitions the advisory already resolved, never by restating an article in this layer. An advisory about a casilla carries that casilla’s own refs (and its binding’s, where a binding is the subject), at parity with the provenance channel beside it: an operator asked to act on a regulated figure needs the provision that establishes it, and prose in message is not a field a machine consumer can route on.

This is the CASILLA-DERIVED path: the subject is the casilla’s (or its binding’s) own computation, and the refs are read off a registry object the advisory already holds, never minted here. For an advisory whose subject is instead a rule the advisory itself is asserting – an eligibility condition governing one of the casilla’s INPUTS, which the casilla’s own refs do not describe – use asserted_legal_refs, not this field. Reading a casilla’s whole-article refs onto a claim about one apartado of it produces a ref coarser than the claim, which is worse than no ref at all: it looks corroborated and is not.

source_refs: tuple[SourceRefId, ...]

Official AEAT source references grounding this advisory’s subject.

The source_refs half of the pair above, carried for the same reason and populated from the same registry definitions. Casilla-derived, at parity with legal_refs.

Legal-catalogue ids the advisory asserts ITSELF, distinct from any casilla.

The ADVISORY-ASSERTED path, not a replacement for legal_refs and not replaced by it – the two coexist because they answer different questions. legal_refs describes what establishes the casilla the advisory happens to be about; this field describes the provision the advisory’s own MESSAGE is a claim about, which is what a message such as “Art. 61 norma 1 halves this” or an eligibility-rule disclosure asserts. That claim is a property of the advisory, not of the casilla it addresses, and a casilla’s whole-article refs are frequently coarser than it.

Every id here is validated at registry build to resolve to a LegalReference catalogue entry – the check a prose-only message could never carry. Declaring an id here is a TAX REVIEW against the provision the message states, never a mechanical derivation from a casilla or binding already in hand: copying the legal_refs construction pattern (reading a casilla’s or binding’s own refs) onto this field reproduces exactly the coarse-ref defect this field exists to avoid.

out_of_window_count: int | None
out_of_window_min_filing_date: date | None
out_of_window_max_filing_date: date | None
out_of_window_summary_message(*, count, min_filing_date, max_filing_date)[source]

Return the standard source-diagnostic message for summarized period exclusions.

Return type:

str

Parameters:
  • count (int)

  • min_filing_date (date)

  • max_filing_date (date)

out_of_window_summary_source_diagnostic(*, source_kind, resolver_id, count, min_filing_date, max_filing_date)[source]

Build one structured source diagnostic for summarized OUTSIDE_PERIOD rows.

Return type:

CalculationSourceDiagnostic

Parameters:
  • source_kind (str)

  • resolver_id (str)

  • count (int)

  • min_filing_date (date)

  • max_filing_date (date)

class CalculationSourceProvenance(**data)[source]

Bases: BaseModel

One primary or contributing node in a resolver-owned provenance graph.

Parameters:

data (Any)

resolver_id: str
resolved_binding_source: BindingSourceKind
contributor_source_kind: str
contributor_binding_source: BindingSourceKind | None
lineage_role: CalculationSourceLineageRole
source_ref: str
parent_source_ref: str | None
fingerprint: str | None
terminal_origin: TerminalOriginClass | None

The class of terminal fact this node actually rests on, as the resolver that produced it knows it. This is the runtime half of the pair the authored (or registration-derived) terminal-origin expectation forms: without it, “the value resolved” and “the value resolved from where the declaration said” are the same observation. None is reserved for a mesh-only source that no provider registration covers – it states that no expectation exists to audit against, never that the origin is unknown.

relation_id: RelationId | None
source_modelo: ModeloId | None
source_filing_year: FilingYear | None
source_periods: tuple[str, ...]
source_casilla_ids: tuple[CasillaId, ...]
legal_refs: tuple[LegalRefId, ...]
source_refs: tuple[SourceRefId, ...]
dependency_treatment: str

The registry’s declared dependency treatment for this carry, empty when the revision declares none. A factual_evidence carry is a fact to reconcile against rather than a figure that settles the return, and a consumer must be able to tell it from a direct_annual_settlement one. Carried here rather than gated here: the value is NOT withheld, because a taxpayer is entitled to a suffered retención and dropping it silently is an over-declaration. Empty means the revision declared no treatment, which is not the same as any particular one and must never be read as one.

class BorradorSourceProvenance(**data)[source]

Bases: BaseModel

Typed borrador-snapshot provenance carried on a source resolution.

The AEAT borrador snapshot is the one source whose downstream consumer (persist_calculation_revision) needs more than the generic CalculationSourceProvenance row: it persists the originating borrador_snapshot_id and the sorted bindings_sourced_from_borrador trace onto the CalculationRevision. Carrying that as ONE typed sub-model keeps the generic CalculationSourceResolution envelope from accreting per-source named fields while preserving the trace as typed data the call site reads directly – never by parsing the borrador:{id}:binding:{bid} provenance source_ref strings.

Parameters:

data (Any)

snapshot_id: SnapshotId
bindings_sourced: tuple[BindingId, ...]
class CalculationSourceResolution(**data)[source]

Bases: BaseModel

Resolved values and provenance returned by one source resolver.

Parameters:
resolver_id: str | CompositeSourceResolverId
owned_sources: tuple[BindingSourceKind, ...]
binding_values: Mapping[BindingId, Decimal]
enum_binding_values: Mapping[BindingId, str]
date_binding_values: Mapping[BindingId, date]
boolean_binding_values: Mapping[BindingId, bool]

Truth values for bindings whose value contract declares the boolean channel.

Its own channel rather than a Decimal("1")/Decimal("0") pair on binding_values, because the two readings a collapsed encoding produces are not the same fact: “this taxpayer holds no right to the mínimo por descendientes” and “this taxpayer’s figure is zero euros” arrive indistinguishable, and the second is a filing-grade amount the first never asserted. A binding whose contract declares BOOLEAN travels here or it does not travel; a Decimal arriving for that contract, or a truth value arriving on the Decimal channel, is refused rather than coerced.

row_binding_values: Mapping[RowBindingKey, RowBindingValue]
row_source_identities: Mapping[RowBindingKey, RowSourceIdentity]
row_casilla_values: Mapping[RowCasillaKey, Decimal]
row_casilla_provenance: Mapping[RowCasillaKey, DirectRowMaterializationProvenance]
relation_values: Mapping[RelationId, Decimal]
unresolved_relation_ids: tuple[RelationId, ...]
unresolved_binding_ids: tuple[BindingId, ...]
bound_inputs_by_casilla_id: Mapping[CasillaId, Decimal]
detail_rows: tuple[ModeloDetailRow, ...]
source_transaction_ids: Sequence[str]
borrador_provenance: BorradorSourceProvenance | None
m303_regimen_simplificado_annual_summary_handoff: M303RegimenSimplificadoAnnualSummaryHandoff | None
diagnostics: tuple[CalculationSourceDiagnostic, ...]
provenance: tuple[CalculationSourceProvenance, ...]
class ModeloSourceResolver(*args, **kwargs)[source]

Bases: Protocol

Application port implemented by one calculation source adapter.

resolver_id: ClassVar[str]

Stable class-level resolver identifier for registration and provenance.

owned_sources: ClassVar[tuple[BindingSourceKind, ...]]

Class-level registry source ownership used by registration and instances.

resolve(context)[source]

Resolve source-backed calculation values for context.

Returns a CalculationSourceResolution carrying resolved binding values, provenance, and any source diagnostics.

Return type:

CalculationSourceResolution

Parameters:

context (CalculationSourceContext)