cadrumo.application.user_profile.bundle_export_contracts module

Typed contracts for the sole portable profile-bundle export service.

This module owns the closed value sets and typed envelopes the single export_profile_bundle() authority composes: the operator ProfileBundleExportPurpose (portable transfer versus subject access), the ProfileBundleExportTransport wire protection, the ProfileBundleExportRequest input, the resolved ProfileBundleExportTarget identity used for same-target locking and operation-state keying, and the published ProfileBundleExportResult.

Data categories are derived from the actual UserProfilePortableExport schema fields and the registry namespaces the bundle carries, never from a static hand-maintained list that silently drifts from what the bundle contains. The field-to-label mapping is still authored here, so it is held exhaustive by construction: every serialized field must be mapped to a category, declared envelope metadata, or declared carried-namespace derived, and an unclassified field refuses rather than dropping out of the disclosed set.

That refusal makes the CARRIED set complete, which is not the same as the archive being complete. The bundle ships under the structured custody profile, so whole namespaces – attachment blobs, purchase invoice evidence, the bucket event history – are deliberately left in encrypted storage. A right-of-access response listing only what it carries would therefore still overstate itself, so bundle_excluded_data_categories() derives the omitted set from the same coverage manifest and the two are always presented together.

The sealed recovery archive is a separate confidentiality and restoration surface and is deliberately absent here.

class ProfileBundleExportPurpose(*values)[source]

Bases: StrEnum

Operator intent for one portable bundle publication.

PORTABLE_TRANSFER
SUBJECT_ACCESS
class ProfileBundleExportTransport(*values)[source]

Bases: StrEnum

Wire protection applied to the published portable bundle.

CLEARTEXT_LOCAL
PASSPHRASE_ENCRYPTED
class ProfileBundleExportRequest(**data)[source]

Bases: BaseModel

Typed request for the sole portable profile export operation.

Parameters:

data (Any)

profile_name: str | None
destination: Path
purpose: ProfileBundleExportPurpose
transport: ProfileBundleExportTransport
passphrase: SecretStr | None
class ProfileBundleExportTarget(**data)[source]

Bases: BaseModel

Resolved destination identity for same-target locking and journal keying.

Two export requests naming the same file resolve to one canonical identity so the service can hold one exclusive lock per target and key a durable operation-state record deterministically, independent of the literal spelling the operator supplied.

Parameters:

data (Any)

destination: Path
property identity: str

Return the canonical absolute-path identity for this target.

class ProfileBundleExportReconcileFailure(**data)[source]

Bases: BaseModel

One crash-recovery operation the reconciliation sweep could not finalise.

destination is None when the journal itself could not be read, so nothing is known about it beyond its identifier. reason is the refusing error’s class name – stable, machine-readable, and carrying no journal contents onto an operator-facing surface.

Parameters:

data (Any)

journal_id: str
destination: str | None
reason: str
class ProfileBundleExportResult(**data)[source]

Bases: BaseModel

Published profile-bundle identity and presentation metadata.

data_categories and excluded_data_categories are stated together on purpose: the first alone reads as a completeness claim the structured custody profile does not support.

reconcile_failures carries whatever the pre-publication crash-recovery sweep could not finalise. It rides the result rather than being logged and dropped, because a journal left behind may still describe cleartext bundle bytes on disk and the operator running the export is the one who needs told.

Parameters:

data (Any)

profile_id: ProfileId
display_name: str
destination: Path
bundle_schema_version: int
purpose: ProfileBundleExportPurpose
transport: ProfileBundleExportTransport
data_categories: tuple[str, ...]
excluded_data_categories: tuple[str, ...]
reconcile_failures: tuple[ProfileBundleExportReconcileFailure, ...]
bundle_data_categories(bundle)[source]

Derive the personal-data categories a bundle carries from its schema.

The category set is computed from the serialized field names present on UserProfilePortableExport and the registry namespaces the bundle’s coverage manifest declares carried, so it cannot silently diverge from the bundle’s actual contents.

Classification of the schema is TOTAL: every serialized field is either mapped to a category, declared envelope metadata, or declared carried-namespace derived. A field belonging to none of the three refuses here rather than being dropped, because this set is what the subject-access response presents as every personal-data category held for the profile – a silently narrowed set would be a false completeness claim to a data subject.

Raises:

ProfileExportError – If the bundle schema carries a field with no declared personal-data classification.

Return type:

tuple[str, ...]

Parameters:

bundle (UserProfilePortableExport)

bundle_excluded_data_categories(bundle)[source]

Derive the personal-data categories a bundle deliberately OMITS.

The portable bundle defaults to the structured custody profile, so every full-custody-only namespace – attachment blobs and manifests, purchase invoice evidence, evidence bundles, apoderado authorisations, the bucket event history – is left in encrypted storage rather than written into the cleartext archive. Those omissions are real and correct, but a right-of-access response that lists only what it CARRIES states a completeness it does not have.

This is the counterpart of bundle_data_categories(), derived from the same coverage manifest the serializer already computes, so the two sets cannot drift from what the bundle actually did.

Return type:

tuple[str, ...]

Parameters:

bundle (UserProfilePortableExport)