Skip to main content

Account storage

Scope and identity

Rust owns the account SQLite database and its authenticated protocol truth. Android provides the app-private directory and account lifecycle. A logical rumor, a signed outer wrapper and a derived product view are distinct objects. Database tables are implementation details, not an Android persistence API.

Supported behavior

Atomic ingestion

shared.storage.atomic — An ingestion transition must commit its accepted records and associated state changes coherently. Invalid input must not become accepted protocol truth. A correlated boundary outcome and its persistence mutations must commit as one transition so that replay can recover a consistent result. External network and file effects do not run inside that transaction.

Logical identity

shared.storage.logical-identity — Repeated receipt of the same logical rumor, including receipt in freshly encrypted outer wrappers, must produce one logical event. Retained wrappers keep their separate provenance links. Neither wrapper ID nor transport arrival order may become an alternative message ID.

Account binding

shared.storage.account-binding — The runtime derives the account identity and database filename from the imported authority. An existing account file must reject another account. Opening the same canonical account file twice in the process must fail rather than create independently mutable account owners.

Persistence semantics

Exact authenticated records are retained separately from projections, relation targets, outgoing intents and account-local state. Product queries derive their answer from those records. A derived search index must be repairable without reinterpreting unauthenticated legacy rows as message truth.

The account-runtime architecture owns concrete tables, migrations, WAL settings and connection policy. Successful SQLite commit under that configured policy does not promise survival of every possible hardware or power failure. Account deletion is a different lifecycle operation from a protocol message deletion.

Observable behavior

A returned mutation result describes committed account state and its revision. Android must not open the SDK database, maintain a second authenticated message cache, or use a received byte count as proof of persistence. Directories, attachment files and WorkManager queues retain their platform ownership.

Verification and limits

Mapped cases cover atomic/idempotent ingestion, correlated boundary commits, multiple wrappers for one rumor, account-file identity mismatch and duplicate open. Text-message history and a selected schema upgrade are verified in the text-message contract.

Disk-full faults, corruption recovery, power interruption, and the complete matrix of historical database versions remain separate evidence requirements. Normal close/reopen tests must not be described as crash injection.

No execution report is bundled with this documentation. Linked test cases describe verification scope; their existence is not a passing result.

InvariantRequired environmentsExecution evidence
shared.storage.atomic
rust-core
rust-hostmissing
2 mapped test cases
  • storage::tests::ingest_is_atomic_idempotent_and_queryablesemantic; sdk, cargo:softchat
  • storage::tests::boundary_frame_outcomes_and_correlated_mutations_commit_as_one_transitionsemantic; sdk, cargo:softchat
Shared requirements
shared.storage.logical-identity
rust-core
rust-hostmissing
1 mapped test cases
  • storage::tests::fresh_wrappers_share_one_logical_rumor_and_retain_every_provenance_edgesemantic; sdk, cargo:softchat
Shared requirements
shared.storage.account-binding
rust-core
rust-hostmissing
2 mapped test cases
  • storage::tests::an_account_file_cannot_be_reopened_for_another_accountsemantic; sdk, cargo:softchat
  • runtime_facade::product_tests::account_derives_path_rejects_duplicate_open_and_erases_on_closesemantic; sdk, cargo:softchat