diff --git a/docs/architecture.md b/docs/architecture.md index 5cb3556..bc1dc14 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -48,6 +48,24 @@ The state directory is intentionally separate from synchronized folders. To remove a folder's synchronization state without touching its files, use `appa forget ` or `appa leave `. +## Version boundaries + +Appa has four deliberately independent version signals. They protect different +persisted or networked formats and should only change with their corresponding +format. + +- The Iroh control-stream ALPN is `appa/sync/3`. It selects a wire-compatible + control protocol before either peer processes a request. +- The invitation protocol version is `5`. It covers the signed invitation + payload and its validation rules. +- The folder protocol version is `2`. It covers the signed folder roster and + manifest model. +- The declarative configuration version is `1`. It covers `appa.toml` only. + +Local SQLite state has no migration ladder by design. Appa is currently a v1 +project and intentionally starts from fresh local state instead of carrying +compatibility code for pre-release formats. + ## Filesystem rules Appa ignores paths matched by `.appaignore` and skips symbolic links. Manifest diff --git a/src/app.rs b/src/app.rs index 876dd0e..56aa89c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -62,6 +62,16 @@ pub enum ConfigAuditAction { Unchanged, } +impl ConfigAuditAction { + pub(crate) fn as_str(&self) -> &'static str { + match self { + Self::Create => "create", + Self::UpdateMode => "update-mode", + Self::Unchanged => "unchanged", + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct ConfigAuditItem { pub path: std::path::PathBuf, diff --git a/src/cli/setup.rs b/src/cli/setup.rs index b627508..0f7728c 100644 --- a/src/cli/setup.rs +++ b/src/cli/setup.rs @@ -1,8 +1,10 @@ use crate::{ - app::{AppaService, ConfigAuditAction}, + app::AppaService, cli::{ConfigCommand, IdentityCommand}, }; +const REPLACE_EXISTING_IDENTITY: bool = true; + pub(super) fn run_identity_command( appa: &AppaService, command: Option, @@ -24,7 +26,7 @@ pub(super) fn run_identity_command( { return Ok(()); } - appa.import_identity(&path, true)?; + appa.import_identity(&path, REPLACE_EXISTING_IDENTITY)?; println!("Imported Appa identity from {}.", path.display()); } } @@ -54,21 +56,9 @@ pub(super) fn run_config(appa: &AppaService, command: ConfigCommand) -> anyhow:: } ConfigCommand::Audit { path } => { for item in appa.audit_config(&path)? { - println!( - "{}\t{}", - config_action_name(&item.action), - item.path.display() - ); + println!("{}\t{}", item.action.as_str(), item.path.display()); } } } Ok(()) } - -fn config_action_name(action: &ConfigAuditAction) -> &'static str { - match action { - ConfigAuditAction::Create => "create", - ConfigAuditAction::UpdateMode => "update-mode", - ConfigAuditAction::Unchanged => "unchanged", - } -} diff --git a/src/config.rs b/src/config.rs index bcb3f31..1af5bd8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,6 +10,7 @@ use uuid::Uuid; use crate::{domain::FolderMode, storage::FolderConfig}; +/// Version of the declarative `appa.toml` format. pub const CONFIG_VERSION: u16 = 1; pub const DEFAULT_CONFIG_PATH: &str = "appa.toml"; diff --git a/src/domain.rs b/src/domain.rs index 666033a..fd5b743 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -19,6 +19,7 @@ pub type FolderId = Uuid; pub type BlobHash = String; pub type RelativePath = String; pub type VersionClock = BTreeMap; +/// Version of the signed folder roster and manifest model. pub const FOLDER_PROTOCOL_VERSION: u16 = 2; #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] diff --git a/src/iroh.rs b/src/iroh.rs index 8a99788..7119914 100644 --- a/src/iroh.rs +++ b/src/iroh.rs @@ -31,6 +31,7 @@ use crate::{ mod handler; use handler::AppaProtocol; +/// ALPN for Appa's Iroh control streams. A new value is wire-incompatible. pub const APPA_ALPN: &[u8] = b"appa/sync/3"; const MAX_CONTROL_MESSAGE_BYTES: usize = 16 * 1024 * 1024; const MAX_CONCURRENT_ANNOUNCEMENTS: usize = 4; diff --git a/src/protocol.rs b/src/protocol.rs index b6d8b28..132a853 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -8,6 +8,7 @@ use iroh::{EndpointAddr, EndpointId, SecretKey, Signature}; use serde::{Deserialize, Serialize}; use time::OffsetDateTime; +/// Version of the signed invitation format and invitation validation rules. pub const PROTOCOL_VERSION: u16 = 5; pub const INVITE_SCHEME: &str = "appa://";