kmp_embedded/migration.rs
1//! Store migration, composed.
2//!
3//! The machinery lives in the storage adapter; what belongs here is the one
4//! decision it deliberately does not make — how a context event becomes
5//! projection mutations. That derivation is the application's, and injecting
6//! it here is what keeps the adapter free of the layer above it and the MCP
7//! binary free of the layer below.
8
9use std::path::Path;
10
11use kmp_adapter_embedded::{EmbeddedKernelStore, StorageEngine, StoreMigrationReceipt};
12use kmp_domain::PortError;
13
14/// Migrates `source_dir` into `destination_dir`, returning what was moved.
15/// The destination is created with the default engine.
16///
17/// The source is never opened for writing and its bytes are verified
18/// unchanged when the migration finishes; the destination must not already
19/// hold a store.
20pub async fn migrate_data_dir(
21 source_dir: &Path,
22 destination_dir: &Path,
23) -> Result<StoreMigrationReceipt, PortError> {
24 migrate_data_dir_to(source_dir, destination_dir, StorageEngine::Redb).await
25}
26
27/// [`migrate_data_dir`] with the destination engine chosen — how a store
28/// changes engines (ADR-018). A redb store becomes a SQLite one that two
29/// agent hosts can share by replaying its history into a fresh directory;
30/// the source stays as it was and the receipt records both layouts.
31pub async fn migrate_data_dir_to(
32 source_dir: &Path,
33 destination_dir: &Path,
34 destination_engine: StorageEngine,
35) -> Result<StoreMigrationReceipt, PortError> {
36 let (_store, receipt) = EmbeddedKernelStore::migrate_data_dir_to(
37 source_dir,
38 destination_dir,
39 destination_engine,
40 kmp_application::projection_mutations_for_context_event,
41 )
42 .await?;
43 Ok(receipt)
44}
45
46/// Migrate once, reopen afterwards. Safe on every start: a destination that
47/// already holds a store is opened as it is, and the returned receipt says
48/// whether this call was the one that migrated it.
49pub async fn open_or_migrate_data_dir(
50 source_dir: &Path,
51 destination_dir: &Path,
52) -> Result<Option<StoreMigrationReceipt>, PortError> {
53 let (_store, receipt) = EmbeddedKernelStore::open_or_migrate_data_dir(
54 source_dir,
55 destination_dir,
56 kmp_application::projection_mutations_for_context_event,
57 )
58 .await?;
59 Ok(receipt)
60}