cadrumo.application.modelo.history module

Chronological bucket-event history assembly at two subject grains.

Surfaces a unified timeline of every event the operator’s work emitted across its lifecycle: creation, renames, calculations, verifications, filings, supersessions, amendments, and discards.

Two subjects are assembled here, and they are genuinely different queries rather than one query with a parameter. assemble_work_unit_history() narrows to a single WorkUnit and walks the object-scoped streams that belong to it. assemble_modelo_lifecycle_history() spans every work unit that filed one modelo, selecting on the modelo subject key events carry in their own payload. They share this module because they share a substrate, a projection row and an ordering; they are not layered on one another, because neither narrows to the other.

The catalogue substrate is the bucket-scoped append-only event log exposed by BucketEventHistoryRepositoryProtocol. Events scoped to a work unit land under four cadrumo.domain.buckets.event.BucketEventObjectType values: WORK_UNIT, CALCULATION_REVISION, VERIFICATION_REPORT, and FILING_RECORD. The assembler walks each related object id and merges the emitted cadrumo.domain.buckets.event.BucketEvent streams in chronological order.

The normalized records remain the source of relational truth: WorkUnit selects the lifecycle root, CalculationRevision identifies calculation attempts under it, VerificationReport identifies verification outcomes for those revisions, and ModeloRecord identifies local filing records. The event history explains how those records changed; it does not replace their catalogues.

The assembler is pure read: no mutation, no remote contact.

See also

cadrumo.application.modelo.work_lifecycle.create_work_unit():

Emits work-unit create, rename, and discard events.

cadrumo.application.modelo.calculate_input.calculate_modelo_work_revision():

Persists calculation revisions and MODELO_CALCULATION_CREATED events.

cadrumo.application.modelo.verification_actions.verify_modelo_revision():

Persists verification reports and verification pass/refusal events.

cadrumo.application.modelo.filing_actions.file_modelo_revision():

Persists local filing records and filing/supersession events.

class WorkUnitHistory(**data)[source]

Bases: BaseModel

Chronologically ordered event timeline for one WorkUnit.

Parameters:

data (Any)

bucket_id: BucketId
work_unit_id: WorkUnitId
events: tuple[BucketEvent, ...]
assemble_work_unit_history(work_unit_id, *, ports)[source]

Return a WorkUnitHistory covering every bucket event scoped to work_unit_id.

Events are merged from object-scoped cadrumo.domain.buckets.event.BucketEvent streams and ordered by bucket_event_order_key(). The work unit itself is loaded to confirm it exists (raising WorkUnitNotFoundError if not) and to discover every CalculationRevision, VerificationReport, and ModeloRecord id that belongs to its lifecycle.

Rows are the validated cadrumo.domain.buckets.event.BucketEvent values themselves, not a restatement of them: a read model repeating that field set can only lose constraints its source already enforces, and this one had already dropped bucket_id, payload_version and the content-address derivation. aeat app modelo work history projects onto its own wire schema at the entrypoint, which is where the loosening belongs.

The function never writes to repositories and never contacts AEAT; mutation and event emission stay with the lifecycle services that produce the underlying records.

See also

cadrumo.domain.buckets.event.BucketEventHistoryCatalogue.for_object():

Supplies each object-scoped event stream merged here.

WorkUnitHistory:

The immutable read model returned to callers.

Return type:

WorkUnitHistory

Parameters:
admitted_modelo_history_event_types()[source]

Return every event type admissible into a per-modelo history, derived from the taxonomy.

Derived at call time from cadrumo.domain.buckets.event.BucketEventType rather than recorded as a literal set, because a literal one drifts silently. The adapter this policy was lifted from held a hand-written set admitting 11 of the 22 live members, and the drift was not theoretical: MODELO_LIVE_EVIDENCE_STAMPED and MODELO_WORK_UNIT_CREATED both carry the modelo, filing_year and period payload keys this history filters on and were both dropped, so the operator was shown a work unit being discarded but never created, under a command documented as covering every lifecycle stage. Nothing failed, because a stale literal reports absence exactly as it reports emptiness.

Admission by type is deliberately broad: it is assemble_modelo_lifecycle_history()’s SUBJECT filter that selects, and an event carrying no modelo payload key self-excludes there. That division is what makes a newly declared event type impossible to drop by omission.

Return type:

frozenset[BucketEventType]

class ModeloLifecycleHistory(**data)[source]

Bases: BaseModel

Chronologically ordered event timeline for one modelo across every work unit.

The sibling of WorkUnitHistory at the other subject grain: that one narrows to a single WorkUnit lifecycle, this one spans every work unit that filed the same modelo, optionally narrowed to one filing year and period.

Parameters:

data (Any)

modelo: ModeloCode
filing_year: int | None
period: str | None
events: tuple[BucketEvent, ...]
assemble_modelo_lifecycle_history(modelo, *, filing_year=None, period=None, ports)[source]

Return a ModeloLifecycleHistory covering every bucket event recorded against modelo.

Serves aeat app modelo history. Admission is the taxonomy-derived set from admitted_modelo_history_event_types(); selection is the event payload’s own modelo subject key, optionally narrowed by filing_year and period.

modelo is validated into ModeloCode before anything is loaded, so a malformed identifier is refused rather than answered with an empty timeline. An empty result then means the modelo has no history, which is a different fact from the identifier never having been able to have one.

Rows are ordered by bucket_event_order_key(), the shared total order every other bucket-event view uses. occurred_at alone does not order these events: emissions inside one operation share an instant by design, so ties would fall through to catalogue mapping order and two readers could render the operator different timelines with nothing invalid anywhere.

The function never writes to repositories and never contacts AEAT.

See also

assemble_work_unit_history():

The same projection at the single-work-unit subject grain.

Return type:

ModeloLifecycleHistory

Parameters: