aeat.adapters.persistence.storage._schema_lineage module¶
Schema-lineage policy for persisted secure-object payloads.
Persisted rows carry the schema_version they were written under, while
the consumer contract names the current version. This module owns the
policy that keeps every version from the durability floor to the current
version readable: the version gate is a ceiling — a version above the
consumer’s current version is refused as written-by-a-newer-application,
and a version below it is readable exactly when the per-hop upgrade chain
up to the current version is complete. Registered upgraders transform
decrypted plaintext payload bytes one version step at a time; ciphertext,
AEAD associated data, and revision-lineage metadata are never rewritten by
a read.
The upgrader registry is EMPTY while every registered namespace sits at
schema version 1. A future schema bump MUST land the one-hop upgrader for
its namespace in the same change, or the lineage gate
(tests/test_schema_lineage.py) fails — that gate is what makes “a
version bump strands years-old taxpayer data” structurally impossible.
SECURE_OBJECT_DURABILITY_FLOOR moves forward only through a
superseding accepted ADR.
See also
secure_object_record_from_row()Row decode path that applies this policy before returning a record.
- Governing vault record
2026-07-08-released-data-durability-adr(version gates become ceilings with an upgrade dispatch).
- SecureObjectSchemaUpgrader¶
Upgrades one decrypted plaintext payload from
from_versiontofrom_version + 1for its namespace. Pure bytes-to-bytes; never touches ciphertext or row metadata.
- SECURE_OBJECT_DURABILITY_FLOOR: Final[int]¶
Oldest secure-object schema version every read path keeps readable. Starts at the from-birth version; moves forward only through a superseding accepted ADR.
- register_secure_object_schema_upgrader(namespace, from_version, upgrader)[source]¶
Register the one-hop payload upgrader for
(namespace, from_version).A schema bump for a namespace lands its upgrader through this function in the same change that raises the namespace’s declared
schema_version; the lineage gate fails until it does.
- deregister_secure_object_schema_upgrader(namespace, from_version)[source]¶
Remove a registered upgrader hop.
Production wiring never removes a hop — dropping one would re-open the stranding gap the lineage gate closes. This exists so tests that register a real upgrader against a scratch namespace can restore the registry in their teardown.
- missing_upgrade_hops(*, namespace, from_version, to_version, upgraders=None)[source]¶
Return the
from_versionof every unregistered hop in the chain.An empty tuple means every step from
from_versiontoto_versionhas a registered upgrader (vacuously so when the versions are equal).
- ensure_schema_version_readable(*, namespace, schema_version, current_version, upgraders=None)[source]¶
Refuse a stored version the current application cannot read.
The gate is a ceiling, not an equality: a version above
current_versionwas written by a newer application and is refused outright; a version below it is accepted exactly when the registered upgrade chain up tocurrent_versionis complete, and refused loudly — naming the first missing hop — when it is not.- Raises:
EnvelopeVersionError – When
schema_versionexceedscurrent_version(future shape) or the upgrade chain has a missing hop (readable only after the missing upgrader ships).- Return type:
- Parameters:
- upgrade_secure_object_payload(payload, *, namespace, from_version, to_version, upgraders=None)[source]¶
Chain-upgrade a decrypted payload from
from_versiontoto_version.Validates the chain first (so a missing hop refuses before any transformation runs), then applies each registered one-hop upgrader in order. Equal versions return the payload unchanged.