cadrumo.adapters.persistence.profile.calculation_revision_override_migration module¶
Forward migration rekeying persisted relation overrides onto binding ids.
A CalculationRevision persists
relation_overrides keyed by the id of the relation the operator overrode,
and that mapping feeds the content-addressed revision id. Relations have since
been absorbed into the binding providers that replaced them, so the runtime
override channel is keyed by the TARGET BINDING id: an override still stored
under a retired relation id matches no binding, contributes nothing, and does so
without saying anything – the operator’s explicit figure silently stops
applying to a filing-bound value.
This module is the forward, deterministic, idempotent stored-data migration that
closes that gap. It rekeys every stored override through the frozen
relation-to-binding join shipped beside it
(relation_binding_join), recomputes each affected revision id through
the canonical identity function so the content address still describes its
contents, and reports the old-to-new revision id pairs it produced.
Properties the migration holds, in the order they matter:
Forward. It reads the retired vocabulary and writes the current one. There is no reverse hop and no dual-read: once a catalogue is migrated, the retired keys are gone from storage.
Deterministic. The join is frozen product data and the id recomputation is the same pure function the write path uses, so the same stored catalogue always yields the same migrated catalogue and the same revision ids.
Idempotent. A key that is already a binding id the join resolves onto is left exactly as it is, so a second run rekeys nothing, recomputes nothing, and returns the catalogue unchanged. Re-running after a partial failure is safe because the write is a single compare-and-swap of the whole singleton.
Non-destructive under doubt. A key that is neither a known relation id nor a known binding id is REFUSED, loudly, naming the key. It is never dropped and never guessed at: an unrecognised override key means either a corpus the frozen join does not describe or a corrupted catalogue, and both are conditions an operator must see rather than a zero a filing can quietly inherit.
The join is many-to-one, so two retired relation ids in one revision can fold onto the same binding. That collapse is accepted only when both stored values are identical; a genuine disagreement is refused for the same reason, since picking a winner would discard an operator-entered figure.
Stored override VALUES are taxpayer figures and appear in no result field and no log record here. The migration reports identifiers only.
- exception OrphanedRelationOverrideError(message=None, *, context=None, translated_message=None)[source]¶
Bases:
CalculationRevisionPersistenceErrorRaised when a stored override key resolves to neither a relation nor a binding.
Carries the offending keys and the owning revision id so an operator can find the catalogue entry. It does NOT carry the override values: they are taxpayer figures, and an error context is one of the surfaces that ends up in a log.
- Parameters:
- Return type:
None
- code¶
- class CalculationRevisionIdRemap(**data)[source]¶
Bases:
BaseModelOne revision’s content address before and after its overrides were rekeyed.
- previous_calculation_revision_id: str¶
- calculation_revision_id: str¶
- work_unit_id: str¶
- class RelationOverrideRekey(**data)[source]¶
Bases:
BaseModelOne override key’s move from its retired relation id onto its binding id.
- Parameters:
calculation_revision_id (str)
relation_id (RelationId)
binding_id (BindingId)
- calculation_revision_id: str¶
The id the owning revision carried BEFORE the rekey, so the pair can be traced back to the catalogue entry the migration read.
- relation_id: RelationId¶
- binding_id: BindingId¶
- class CalculationRevisionOverrideMigrationResult(**data)[source]¶
Bases:
BaseModelWhat one migration run changed, reported as identifiers only.
rekeyed_revisionsis empty on an already-migrated catalogue, which is how a caller distinguishes a no-op re-run from a first run.- Parameters:
catalogue (CalculationRevisionCatalogue)
rekeyed_revisions (tuple[CalculationRevisionIdRemap, ...])
rekeyed_override_keys (tuple[RelationOverrideRekey, ...])
- catalogue: CalculationRevisionCatalogue¶
- rekeyed_revisions: tuple[CalculationRevisionIdRemap, ...]¶
- rekeyed_override_keys: tuple[RelationOverrideRekey, ...]¶
- unchanged_revision_ids: tuple[str, ...]¶
- rekey_calculation_revision_overrides(catalogue, *, operation)[source]¶
Rekey every stored relation override onto its binding id, in memory.
The pure half of the migration: no storage is touched, so this is the function tests and the repository-facing entry point share. A revision whose overrides are already binding-keyed – including every revision with no overrides at all – is carried through untouched and its content address is not recomputed, which is what makes a second run a no-op.
- Parameters:
catalogue (
CalculationRevisionCatalogue) – The catalogue as read from storage.operation (
PinnedAuthorityOperation) – Existing generation-pinned authority operation.
- Return type:
- Returns:
The migrated catalogue plus the identifier-only record of what moved.
- Raises:
OrphanedRelationOverrideError – A stored override key could not be resolved, or two keys folded onto one binding with different values.
- migrate_stored_relation_overrides_to_binding_ids(repository, *, operation)[source]¶
Rekey one profile’s stored overrides and persist the result atomically.
The read is revision-guarded and the write is the singleton’s own compare-and-swap, so a calculate run committing between the two makes this call fail rather than discard that run’s revision. A failed run leaves the stored catalogue exactly as it was and can simply be re-run.
An already-migrated catalogue is not written back at all: the migration is idempotent in storage as well as in memory, so re-running it does not churn the row’s revision lineage.
- Parameters:
repository (
CalculationRevisionCatalogueRepositoryProtocol) – The bucket-bound calculation-revision catalogue repository.operation (
PinnedAuthorityOperation) – Existing generation-pinned authority operation.
- Return type:
- Returns:
The identifier-only record of what moved, carrying the migrated catalogue.
- Raises:
OrphanedRelationOverrideError – A stored override key could not be resolved to a binding.