cadrumo.application.user_profile.capsule_record module¶
Authenticated current-profile records in the capsule-local secure-object DB.
The profile record is one encrypted USER_PROFILE_VALUE_NAMESPACE row in
the capsule’s normal SQLite substrate. It is never a sidecar JSON document.
Every create or replacement co-writes the row and the canonical bucket-event
history through one SecureObjectRepository.apply_batch transaction.
- exception ProfileRecordConflictError(message=None, *, context=None, translated_message=None)[source]¶
Bases:
UserProfileErrorThe authenticated record changed before its CAS command committed.
Joins the
UserProfileErrorfamily so the refusal binds to the error registry and one clause still catches the whole user-profile surface.ValueErroris retained deliberately: it is load-bearing ancestry here, not decoration – seeProfileRecordIntegrityError.- Parameters:
- Return type:
None
- code¶
- exception ProfileRecordIntegrityError(message=None, *, context=None, translated_message=None)[source]¶
Bases:
UserProfileErrorA current-record row or its event witness is malformed or mis-bound.
Joins the
UserProfileErrorfamily so the refusal binds to the error registry.ValueErroris retained because the lifecycle restore path converts a failed authenticated validation into its own refusal through aValueErrorarm; dropping the builtin ancestry would let the inner refusal escape that conversion and reach the operator naming a stage it never reached.- Parameters:
- Return type:
None
- code¶
- class ProfileRecordCommandEvent(**data)[source]¶
Bases:
BaseModelNon-secret command witness co-written into canonical bucket history.
- Parameters:
event_type (BucketEventType)
occurred_at (str)
- event_type: BucketEventType¶
- occurred_at: str¶
- payload: Mapping[str, str]¶
- class LoadedProfileRecord(record, row_revision_id, previous_row_revision_id, event_id)[source]¶
Bases:
objectOne verified current record together with its secure-object CAS token.
- Parameters:
record (UserProfileRecord)
row_revision_id (str)
previous_row_revision_id (str | None)
event_id (str)
-
record:
UserProfileRecord¶
- class ProfileRecordSession(profile_id, envelope_digest, password_generation, dek_epoch, _dek, profile_decode_context)[source]¶
Bases:
objectShort-lived authority bound to one unlocked custody envelope and DEK.
- Parameters:
-
profile_decode_context:
ProfileDecodeContext¶
- classmethod from_envelope(*, envelope, dek, profile_decode_context)[source]¶
Create a record authority from an unlocked envelope and its DEK.
- Return type:
- Parameters:
envelope (ProfileCustodyEnvelopePort)
dek (bytes)
profile_decode_context (ProfileDecodeContext)
- close()[source]¶
Zeroise the DEK in place, retiring this authority without discarding it.
- Return type:
- property closed: bool¶
Whether the DEK has been zeroised, so this authority can no longer decrypt.
Retirement is destructive but not observable from the outside:
closezeroises the key in place and leaves the object, its UUID and its envelope binding intact, so a holder cannot tell a retired authority from a live one by looking at it. Anything deciding whether to REUSE a session has to ask, and before this predicate existed the only way to find out was to ask for the key and catch the refusal – an integrity error raised at the point of use, far from the reuse decision that caused it.Read as the absence of key material rather than as a separate flag, so there is one definition of retired rather than a boolean a future
closevariant could forget to set.
- encryption_key()[source]¶
Return the DEK only to the local secure-object session bridge.
- Return type:
- create_context()[source]¶
Reuse this session’s pinned generation for a replacement write.
- Return type:
- assert_initial_record(record)[source]¶
Validate that a record is the first authenticated revision for this session.
Core types:
UserProfileRecord.- Return type:
- Parameters:
record (UserProfileRecord)
- assert_replacement(current, replacement)[source]¶
Validate that a replacement advances the authenticated current record.
Core types:
UserProfileRecord.- Return type:
- Parameters:
current (UserProfileRecord)
replacement (UserProfileRecord)
- write_provenance(record)[source]¶
Return the strict row header cross-bound to the encrypted payload.
Core types:
UserProfileRecord.- Return type:
- Parameters:
record (UserProfileRecord)
- assert_row_binding(raw, record)[source]¶
Authenticate the row header against the unlocked envelope and record.
Core types:
UserProfileRecord.- Return type:
- Parameters:
record (UserProfileRecord)
- profile_record_object_key(profile_id)[source]¶
Return the registered natural key for the one current profile record.
- class ProfileRecordStore(*, session, root=None)[source]¶
Bases:
objectStrict current-record storage over the capsule’s canonical secure DB.
- Parameters:
session (ProfileRecordSession)
root (Path | None)
- history()[source]¶
Return the append-only authenticated history for this profile record.
- Return type:
- create_initial(record, *, stage_path)[source]¶
Write revision one and its creation event before the stage commit marker.
Core types:
UserProfileRecord.- Return type:
- Parameters:
record (UserProfileRecord)
stage_path (Path)
- validate_staged_database(*, stage_path)[source]¶
Refuse a restore stage unless its exact current record is authenticated.
- Return type:
- Parameters:
stage_path (Path)
- replace(*, replacement, event, expected_revision, expected_content_digest)[source]¶
CAS-replace the sole current row and append its event in one transaction.
Core types:
UserProfileRecord.- Return type:
- Parameters:
replacement (UserProfileRecord)
event (ProfileRecordCommandEvent)
expected_revision (int)
expected_content_digest (str)
- rehead_under_rotated_envelope(*, rotated, event)[source]¶
Re-publish the current row’s witness under a re-wrapped envelope.
A passphrase rotation re-mints the password envelope over the SAME data key. The row’s
write_provenancefolds the envelope digest and the password generation, so after the swap the stored witness names a wrapper that no longer exists and every read refuses. Nothing about the RECORD changed, but its custody witness must.Read and write use different sessions on purpose, and that asymmetry is the whole method: the stored row can only be authenticated by the session that wrote it, while the replacement can only be authenticated afterwards by the rotated one. Both address the same profile and hold the same key – rotation does not re-key – so the secure-object repository is indifferent to which one opens it.
The revision advances rather than being rewritten in place. A row rewritten under its own revision would leave a revision-one record carrying a predecessor row, which the initial-lineage assertion refuses outright; and the rotation is a real lifecycle fact that ought to appear in the profile’s history rather than mutate its past silently. Content is preserved exactly, so the advance records the custody change and nothing else.
- Return type:
- Parameters:
rotated (ProfileRecordSession)
event (ProfileRecordCommandEvent)
- stage_initial_profile_record_database(*, stage_path, root, session, record)[source]¶
Materialise the canonical encrypted DB before the custody commit marker exists.
Core types:
UserProfileRecord.- Return type:
- Parameters:
stage_path (Path)
root (Path)
session (ProfileRecordSession)
record (UserProfileRecord)
- validate_staged_profile_record_database(*, stage_path, root, session)[source]¶
Authenticate the exact staged record before restore publication can continue.
- Return type:
- Parameters:
stage_path (Path)
root (Path)
session (ProfileRecordSession)