cadrumo.application.user_profile.bundle_export_operation module

Durable, non-secret operation state for profile-bundle publication.

The single export_profile_bundle() authority records the progress of one publication as a credential-free journal file so a crash in any publication window recovers honestly. Journal files live under <storage-root>/profile-export-operations, deliberately OUTSIDE both the target artifact and any bucket directory: the target file is the sensitive cleartext bundle, so the operation state that describes it carries no bundle bytes, no passphrase, and no raw tax id – only the resolved target identity, purpose, transport, schema version, derived data categories, and the payload digest.

A PREPARED journal records that a bundle was serialized to a staged temporary file but not yet atomically published; a COMPLETED journal records that the atomic replace and parent-directory fsync durably landed the target, with the completion event still owed until the journal is cleared. Reconciliation completes a durably-published operation – a COMPLETED one, or a PREPARED one whose destination content matches the recorded digest (the replace landed but the COMPLETED transition did not) – by emitting the owed event, and clears a PREPARED operation that never published as an orphan.

This is a distinct surface from the sealed recovery archive, which owns its own confidentiality and restoration semantics and is not folded in here.

profile_export_staged_path(destination, *, process_id, nonce)[source]

Derive the one staged sibling path an export operation may own.

Return type:

Path

Parameters:
is_canonical_profile_export_staged_path(destination, staged_path)[source]

Return whether staged_path is this destination’s generated staging sibling.

Return type:

bool

Parameters:
class ProfileBundleExportOperationStatus(*values)[source]

Bases: StrEnum

Lifecycle state of one durable profile-export publication.

PREPARED
COMPLETED
class ProfileBundleExportOperation(**data)[source]

Bases: BaseModel

Credential-free durable record of one publication’s progress.

content_sha256 is the digest of the exact staged payload bytes. Because publication moves those bytes into place with os.replace() rather than re-serializing, the published target’s digest equals this value, so a reconciliation can tell a PREPARED operation whose replace already landed (published, digest matches) from a genuine orphan (digest absent or divergent) without a separate durable marker. event_occurred_at is the fixed timestamp the completion event is derived from, so a live publish and a later reconciliation emit the byte-identical (idempotent) event.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

operation_id: Hex64Str
status: ProfileBundleExportOperationStatus
profile_id: ProfileId
display_name: str
target_identity: str
destination: str
staged_path: str
content_sha256: ContentDigest
purpose: ProfileBundleExportPurpose
transport: ProfileBundleExportTransport
bundle_schema_version: int
data_categories: tuple[str, ...]
excluded_data_categories: tuple[str, ...]
started_at: datetime
updated_at: datetime
event_occurred_at: datetime
derive_export_operation_id(*, profile_id, target_identity, purpose)[source]

Derive one clock-free operation identifier for a target publication.

The identifier folds the profile, the resolved target identity, and the purpose so a retried export to the same file for the same purpose reconciles to the same journal rather than accreting orphan records. The timestamp is a non-identity progress field and is deliberately excluded.

Return type:

str

Parameters:
class UnreadableExportJournal(**data)[source]

Bases: BaseModel

One journal file the repository could not turn into an operation.

Carries the file’s own identifier and the refusing error’s class name rather than its message: the id is what an operator needs to find the file, and the class name is a stable machine-readable reason that carries no journal contents.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

journal_id: str
reason: str
class ProfileBundleExportJournalScan(**data)[source]

Bases: BaseModel

Every journal the repository could read, and every one it could not.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

operations: tuple[ProfileBundleExportOperation, ...]
unreadable: tuple[UnreadableExportJournal, ...]
exception ProfileBundleExportJournalError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Base failure for profile-export journal persistence and validation.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception ProfileBundleExportJournalNotFoundError(message=None, *, context=None, translated_message=None)[source]

Bases: ProfileBundleExportJournalError

Raised when a requested export journal does not exist.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception ProfileBundleExportJournalCorruptError(message=None, *, context=None, translated_message=None)[source]

Bases: ProfileBundleExportJournalError

Raised for unreadable, malformed, schema-invalid, or mismatched journals.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
class ProfileBundleExportJournalRepository(*, settings=None, storage_root=None)[source]

Bases: JournalRepositoryBase[ProfileBundleExportOperation]

Persist credential-free export journals as atomic individual files.

The repository provides no publication orchestration and no cryptographic authenticity guarantee; it is the durable state store the publication service and its reconciliation read and write. The atomic read/write substrate is inherited from JournalRepositoryBase; this class adds journal deletion, an isolating scan, and prepared-state selection.

Parameters:
  • settings (Settings | None)

  • storage_root (Path | None)

delete(operation_id)[source]

Remove one journal file once its operation is reconciled or complete.

Return type:

None

Parameters:

operation_id (str)

scan()[source]

Load every readable journal, reporting the unreadable ones separately.

The isolating counterpart to JournalRepositoryBase.list(). A journal that is corrupt, schema-invalid, identity-mismatched, or unreadable does not abort the walk and does not disappear either: it is reported in unreadable so the caller can surface it rather than silently skipping a record that may still describe cleartext bytes on disk.

Return type:

ProfileBundleExportJournalScan

prepared()[source]

Return journals still in the PREPARED (unpublished) state.

Return type:

tuple[ProfileBundleExportOperation, ...]