Skip to content

feat: durable MLS storage folded into a single ChatStore#158

Draft
osmaczko wants to merge 1 commit into
mainfrom
feat/mls-storage
Draft

feat: durable MLS storage folded into a single ChatStore#158
osmaczko wants to merge 1 commit into
mainfrom
feat/mls-storage

Conversation

@osmaczko

@osmaczko osmaczko commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Implements issue #112: MLS group state must survive process restarts. The MLS
provider hardcoded an in-memory store separate from the chat store, so a restart
lost every group. Fold the OpenMLS StorageProvider into libchat's own ChatStore
so one durable store holds both chat state and MLS group state.

  • storage: ChatStore subsumes StorageProvider<CURRENT_VERSION>, so a ChatStore is
    the whole durable-storage contract (identity/ephemeral/conversation/ratchet
    sub-stores plus the MLS key-value surface).
  • chat-sqlite: ChatStorage implements StorageProvider over an mls_kv table
    (migration 003_mls_storage), a byte-faithful port of MemoryStorage with decode
    errors surfaced instead of unwrapped and the reference clear_proposal_queue
    orphan-key bug fixed. The separate SqliteMlsStorage type is removed.
  • conversations: MlsPqProvider becomes a transient view borrowing the shared
    store and a long-lived crypto backend, so the store stays singly owned;
    ServiceContext hands it out via mls_provider(). ExternalServices drops its ST
    associated type, leaving one CS. GroupV2/de_mls's thread-safe-error bound is
    restated on CS because an associated-type bound does not elaborate through a
    supertrait.
  • client: the store is always ChatStorage, so fix it as such and drop the
    vestigial store generic from ChatClient and the builder. Retire the stubbed
    in-memory MemStore in favour of ChatStorage::in_memory().
  • GroupV1 conversations resume across a restart through the existing
    MlsGroup::load path, proven by a drop-and-reload integration test.

@osmaczko osmaczko force-pushed the feat/mls-storage branch from 8d86689 to d025390 Compare July 1, 2026 17:50
@osmaczko osmaczko changed the title feat: durable MLS storage via a pluggable StorageProvider feat: durable MLS storage folded into a single ChatStore Jul 1, 2026
Implements issue #112: MLS group state must survive process restarts. The MLS
provider hardcoded an in-memory store separate from the chat store, so a restart
lost every group. Fold the OpenMLS StorageProvider into libchat's own ChatStore
so one durable store holds both chat state and MLS group state.

- storage: ChatStore subsumes StorageProvider<CURRENT_VERSION>, so a ChatStore is
  the whole durable-storage contract (identity/ephemeral/conversation/ratchet
  sub-stores plus the MLS key-value surface).
- chat-sqlite: ChatStorage implements StorageProvider over an mls_kv table
  (migration 003_mls_storage), a byte-faithful port of MemoryStorage with decode
  errors surfaced instead of unwrapped and the reference clear_proposal_queue
  orphan-key bug fixed. The separate SqliteMlsStorage type is removed.
- conversations: MlsPqProvider becomes a transient view borrowing the shared
  store and a long-lived crypto backend, so the store stays singly owned;
  ServiceContext hands it out via mls_provider(). ExternalServices drops its ST
  associated type, leaving one CS. GroupV2/de_mls's thread-safe-error bound is
  restated on CS because an associated-type bound does not elaborate through a
  supertrait.
- client: the store is always ChatStorage, so fix it as such and drop the
  vestigial store generic from ChatClient and the builder. Retire the stubbed
  in-memory MemStore in favour of ChatStorage::in_memory().
- GroupV1 conversations resume across a restart through the existing
  MlsGroup::load path, proven by a drop-and-reload integration test.
@osmaczko osmaczko force-pushed the feat/mls-storage branch from d025390 to 7332c15 Compare July 1, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant