commit 205ba4d6eb71100a28f4d8cf47ee613b42a9938d
parent 3f35c869c827b35b27e7a7d789d409e6c3def6a8
Author: triesap <tyson@radroots.org>
Date: Thu, 6 Aug 2026 00:11:47 +0000
architecture: govern the consolidated crate catalog
- Add immutable v2 release and Rust consolidation authorities.
- Catalog all current and reserved packages with source and license provenance.
- Enforce Cargo, dependency-tier, visibility, naming, and retirement parity.
- Generate digest-bound package, platform, and release inventories atomically.
Diffstat:
10 files changed, 2482 insertions(+), 8 deletions(-)
diff --git a/contracts/consolidation/architecture.v1.toml b/contracts/consolidation/architecture.v1.toml
@@ -0,0 +1,28 @@
+schema_version = 1
+consolidation_id = "radroots.rust.consolidation.v1"
+architecture = "radroots.crates.release.v2"
+canonical_rust_repository = "https://github.com/radrootslabs/lib"
+donor_repositories = [
+ "https://github.com/radrootslabs/sdk",
+ "https://github.com/radrootslabs/app_rt",
+ "https://github.com/radrootslabs/studio_app",
+]
+consumer_repositories = [
+ "https://github.com/radrootslabs/sdk",
+ "https://github.com/radrootslabs/studio_app",
+]
+source_retirement_requires = [
+ "canonical_import_committed",
+ "history_evidence_green",
+ "compatibility_evidence_green",
+ "consumer_cutover_green",
+ "rollback_rehearsal_green",
+ "explicit_retirement_authorization",
+]
+repository_archival_requires = [
+ "all_mobile_consumers_canonical",
+ "zero_reusable_source",
+ "remote_master_reconciled",
+ "rollback_bundle_verified",
+ "explicit_archival_authorization",
+]
diff --git a/contracts/crates/catalog.v1.toml b/contracts/crates/catalog.v1.toml
@@ -0,0 +1,1250 @@
+schema_version = 1
+schema = "radroots.workspace.catalog.v1"
+architecture = "radroots.crates.release.v2"
+consolidation = "radroots.rust.consolidation.v1"
+version = "0.1.0-alpha"
+rust_version = "1.97.1"
+edition = "2024"
+resolver = "3"
+public_package_count = 19
+package_count = 60
+digest_algorithm = "sha256-raw-bytes-v1"
+source_tree_digest_algorithm = "sha256-git-ls-tree-r-v1"
+source_provenance_policy = "immutable_after_source_retirement"
+provenance_correction_contract = "approved_correction_record_required"
+retired_packages = [
+ "radroots_app_core",
+ "radroots_app_ffi",
+ "radroots_app_wasm",
+ "radroots_app_bindgen",
+ "radroots-studio-domain",
+ "radroots-studio-application",
+ "radroots-studio-nostr",
+ "radroots-studio-storage",
+ "radroots-studio-ffi",
+ "radroots-studio-uniffi-bindgen",
+ "radroots_sdk_xtask",
+]
+
+[[package]]
+name = "radroots_core"
+path = "crates/core"
+state = "active"
+tier = "foundation"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["core"]
+permitted_dependency_tiers = ["foundation"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/core"
+source_tree_sha256 = "2b1c006eb548b1e3671d4bae1cf0202900909c40affe224e4f5dd098de3fe7c7"
+compatibility = ["rust_api", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_identity"
+path = "crates/identity"
+state = "active"
+tier = "foundation"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["identity"]
+permitted_dependency_tiers = ["foundation"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/identity"
+source_tree_sha256 = "6da935d01da21254f13477cfa45fc44e3bc48dc3e3a8786f7dd8d528fc51b5b9"
+compatibility = ["rust_api", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_blossom"
+path = "crates/blossom"
+state = "active"
+tier = "foundation"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["protocol"]
+permitted_dependency_tiers = ["foundation"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/blossom"
+source_tree_sha256 = "09cd49bdca7432ba0bab915950a6c7fe882ee75f6e70c8916c1f04030f27745d"
+compatibility = ["rust_api", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_protocol"
+path = "crates/protocol"
+state = "active"
+tier = "foundation"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["protocol"]
+permitted_dependency_tiers = ["foundation"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/protocol"
+source_tree_sha256 = "05f7c372daec2da2c2e249bc10a645fbe11bb36ca4f45b7ebb52094fb39dc593"
+compatibility = ["rust_api", "wire", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_event"
+path = "crates/event"
+state = "active"
+tier = "domain"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["event"]
+permitted_dependency_tiers = ["foundation", "domain"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/event"
+source_tree_sha256 = "bfe3e6ece4d728ba9e5b6476376c172d621a310788c420e33f81a4cdfc3067ef"
+compatibility = ["rust_api", "wire", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_event_codec"
+path = "crates/event_codec"
+state = "active"
+tier = "domain"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["event"]
+permitted_dependency_tiers = ["foundation", "domain"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/event_codec"
+source_tree_sha256 = "6b51309e57b163d7577ec4b7f0fd8e28b2c98aa44cb7fe51a38346300e6078f7"
+compatibility = ["rust_api", "wire", "generated", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_trade"
+path = "crates/trade"
+state = "active"
+tier = "domain"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["trade"]
+permitted_dependency_tiers = ["foundation", "domain"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/trade"
+source_tree_sha256 = "10c873d05c12255ebbdba57772688bb033a183f569959184f1fe9dac248b9bda"
+compatibility = ["rust_api", "behavior", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_signing"
+path = "crates/signing"
+state = "active"
+tier = "spi"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["signing"]
+permitted_dependency_tiers = ["foundation", "domain", "spi"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/signing"
+source_tree_sha256 = "55d4e9f719358a3bb5287688947a34773646aabc7b902a6da790b5c4c0d72026"
+compatibility = ["rust_api", "security", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_transport"
+path = "crates/transport"
+state = "active"
+tier = "spi"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["transport"]
+permitted_dependency_tiers = ["foundation", "domain", "spi"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/transport"
+source_tree_sha256 = "4f39941e5a3c7ec82e179198900541dfcd66ef6bfcffcc7de7e89b604461598a"
+compatibility = ["rust_api", "wire", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_secrets"
+path = "crates/secrets"
+state = "active"
+tier = "spi"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["portable", "public_native"]
+owners = ["security"]
+permitted_dependency_tiers = ["foundation", "domain", "spi"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/secrets"
+source_tree_sha256 = "f20923b87e73a65db157f75342fa6814a0b90707e2210f387f9aaddbd2705cf2"
+compatibility = ["rust_api", "security", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_storage"
+path = "crates/storage"
+state = "active"
+tier = "spi"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["portable", "public_native"]
+owners = ["storage"]
+permitted_dependency_tiers = ["foundation", "domain", "spi"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/storage"
+source_tree_sha256 = "383e648daaded9c02d8bf64164697fbd23f0c9a82887b0210a487c1803ccdf91"
+compatibility = ["rust_api", "data", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_nostr"
+path = "crates/nostr"
+state = "active"
+tier = "adapter"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["nostr"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/nostr"
+source_tree_sha256 = "5d526e5aa8c98b71218a341346a70250d278866b6818204b8a78b9772508bb0e"
+compatibility = ["rust_api", "wire", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_nostr_connect"
+path = "crates/nostr_connect"
+state = "active"
+tier = "adapter"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native"]
+owners = ["nostr"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/nostr_connect"
+source_tree_sha256 = "10cb6c86a37d11fdf09aa8f47486e504b7ad94d2e0ba92f241442ec10a4578b5"
+compatibility = ["rust_api", "wire", "security", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_storage_sqlite"
+path = "crates/storage_sqlite"
+state = "active"
+tier = "adapter"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["portable", "public_native"]
+owners = ["storage"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/storage_sqlite"
+source_tree_sha256 = "1ba1c8adc6741e931220eae5fdcef7a05894e3d8276a869448ab6583b13b93e9"
+compatibility = ["rust_api", "data", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_transport_nostr"
+path = "crates/transport_nostr"
+state = "active"
+tier = "adapter"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["portable", "public_native"]
+owners = ["transport"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/transport_nostr"
+source_tree_sha256 = "1f8b471ee468200dc61e8452184d213906d3ca4b13e64b311aca7ad40fdacac6"
+compatibility = ["rust_api", "network", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_geonames"
+path = "crates/geonames"
+state = "active"
+tier = "adapter"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["portable", "public_native"]
+owners = ["geonames"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/geonames"
+source_tree_sha256 = "1ae21934d6b6dadf4baebad3f4658c6cfe04d4abb4b36f869644c87cebacdc3a"
+compatibility = ["rust_api", "data", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_sync"
+path = "crates/sync"
+state = "active"
+tier = "orchestration"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["portable", "public_native"]
+owners = ["sync"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/sync"
+source_tree_sha256 = "23a16aaddc8366fd7ad6461e97103de03593d23a16687a7a2b6f86fc3a683c53"
+compatibility = ["rust_api", "behavior", "features", "package"]
+replaces = []
+
+[[package]]
+name = "radroots_nostrdb"
+path = "crates/nostrdb"
+state = "active"
+tier = "preview"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/nostrdb"
+source_tree_sha256 = "f1824eb3fe9f02046aabe40319d2c346de499c74a90aca11fe648e76bc8e744b"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_transport_reticulum"
+path = "crates/transport_reticulum"
+state = "active"
+tier = "preview"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/transport_reticulum"
+source_tree_sha256 = "590a69dabb65e891900884e5b67636d0a2e83f40a8d92fc4fdf3fb68bf9ac493"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_simplex_app_store"
+path = "crates/simplex_app_store"
+state = "active"
+tier = "preview"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/simplex_app_store"
+source_tree_sha256 = "43d51e5601d16666faa32607da732e8c48d9c75dee8c308c782b90da5fa8fdf5"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_simplex_agent_proto"
+path = "crates/simplex_agent_proto"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/simplex_agent_proto"
+source_tree_sha256 = "9ba0704f166f7cd3aa08f4cb8c3548f0da4d641266f5c6ac3691db0ebb2576f2"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_simplex_chat_proto"
+path = "crates/simplex_chat_proto"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/simplex_chat_proto"
+source_tree_sha256 = "1ba255a084e8962c472c5d0fb89592b8e775cc1017827ff13d18315e6bebf0d9"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_simplex_smp_crypto"
+path = "crates/simplex_smp_crypto"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/simplex_smp_crypto"
+source_tree_sha256 = "618926bd97e2b8e68732aff55b56817ee942ae66fbd4670a8a87ce9c28f37a93"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_simplex_smp_proto"
+path = "crates/simplex_smp_proto"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/simplex_smp_proto"
+source_tree_sha256 = "4d3580ab580ec4008af0f1b6c45cfaf418b8f8f112d80e2c6338c83aba44c730"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_simplex_smp_transport"
+path = "crates/simplex_smp_transport"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/simplex_smp_transport"
+source_tree_sha256 = "50d902c20901de5647e8a3dbe359b9d79eb336d8952c363b914f51ee39240f24"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_replica_schema"
+path = "crates/replica_schema"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/replica_schema"
+source_tree_sha256 = "65c91da5221a98f33d134ff19d760dc7185c33985574c127e7e3ffe9b6636538"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_replica_store"
+path = "crates/replica_store"
+state = "active"
+tier = "preview"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/replica_store"
+source_tree_sha256 = "6b4761d89269e5468b924c30d2b1f9da4ae42adcb5c6ae85bd65c2c47a565e08"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_replica_sync"
+path = "crates/replica_sync"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "fixture"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/replica_sync"
+source_tree_sha256 = "8c957b0bc99c690c40d74cf747ece37b9f5b2d6a4849171fc2d0cce675850c90"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_mesh"
+path = "crates/mesh"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/mesh"
+source_tree_sha256 = "2aa1e901b21ecaa135e7af10ef96270aeae0a19eff5e5006ffdcd1aca62e7979"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_mesh_agent_client"
+path = "crates/mesh_agent_client"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/mesh_agent_client"
+source_tree_sha256 = "37a7a74761d6922264787d9dfc22c01453c423e0dfcece854a37ee9df725232a"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_mesh_agent_proto"
+path = "crates/mesh_agent_proto"
+state = "active"
+tier = "preview"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["preview"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/mesh_agent_proto"
+source_tree_sha256 = "85767b6a613bd1e167484bb60221107c43648472e4cebfdcbeda7e4bc38f9c57"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_runtime_paths"
+path = "crates/runtime_paths"
+state = "active"
+tier = "runtime"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["runtime"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "runtime"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/runtime_paths"
+source_tree_sha256 = "59ed1e101555715827c33e7781ff4993149b2177011ab1401f5cd832a1666120"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_runtime_distribution"
+path = "crates/runtime_distribution"
+state = "active"
+tier = "runtime"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["runtime"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "runtime"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/runtime_distribution"
+source_tree_sha256 = "412a69a157253216fc08daa967e3de4f980b35cb6ef098baa4a77d74175ba193"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_runtime_manager"
+path = "crates/runtime_manager"
+state = "active"
+tier = "runtime"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["preview"]
+owners = ["runtime"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "runtime"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/runtime_manager"
+source_tree_sha256 = "d6df1cfee50affc1e8bb3fcfbf283873c0442031d90db08da31bf3d668547809"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_sql_core"
+path = "crates/sql_core"
+state = "active"
+tier = "adapter"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native", "wasm32"]
+groups = ["preview", "wasm"]
+owners = ["storage"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/sql_core"
+source_tree_sha256 = "18e107bdeeee8761f731a1c389e475e5caebbd2a958c0646d0c6aa5f8c95b8dc"
+compatibility = ["package_private"]
+replaces = []
+
+[[package]]
+name = "radroots_test_fixtures"
+path = "crates/test_fixtures"
+state = "active"
+tier = "fixture"
+visibility = "private_fixture"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["preview"]
+owners = ["testing"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "runtime", "fixture"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "crates/test_fixtures"
+source_tree_sha256 = "763e4af22fbf5e7f11709c1b00f55569dbe3ebf8b679bdb937d462d576f02524"
+compatibility = ["fixtures"]
+replaces = []
+
+[[package]]
+name = "xtask"
+path = "tools/xtask"
+state = "active"
+tier = "tool"
+visibility = "private_tool"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["tools"]
+owners = ["architecture"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "runtime", "fixture", "tool"]
+source_repository = "https://github.com/radrootslabs/lib"
+source_revision = "3f35c869c827b35b27e7a7d789d409e6c3def6a8"
+source_path = "tools/xtask"
+source_tree_sha256 = "2846b559151c835b1a561153166074625a8430130b2f1adcaf1a358eb0da20ff"
+compatibility = ["command_surface"]
+replaces = []
+
+[[package]]
+name = "radroots_sdk"
+path = "crates/sdk"
+state = "reserved_import"
+tier = "sdk"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native", "sdk"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/sdk"
+source_tree_sha256 = "6cc78f544bd0a0d74783cbba118ea4815ce4b4bd094433193844621352411efb"
+compatibility = ["rust_api", "features", "package", "product"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots"
+path = "crates/radroots"
+state = "reserved_import"
+tier = "facade"
+visibility = "public_release"
+publish = true
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["any"]
+groups = ["portable", "public_native", "sdk"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/radroots"
+source_tree_sha256 = "7c9b4392eb7e8d8e799f4a62c9886f349161bad440659beb0d1a739911ab1425"
+compatibility = ["rust_api", "features", "package", "product"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_core_bindings"
+path = "crates/core_bindings"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["sdk", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "codegen"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/core_bindings"
+source_tree_sha256 = "f1a72bde7364179687bbdf6c4dacddacd504c52a884af941ce3557bae27ee981"
+compatibility = ["generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_event_bindings"
+path = "crates/event_bindings"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["sdk", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "codegen"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/event_bindings"
+source_tree_sha256 = "32f23a76a5c135de841cae623a28de3424dace3b6ba46af8c2cccc35b7c62f09"
+compatibility = ["generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_identity_bindings"
+path = "crates/identity_bindings"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["sdk", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "codegen"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/identity_bindings"
+source_tree_sha256 = "a0cf1539805704195cf82f9ffffa06e443a9c1cabd90a47bfcf6110f20549acd"
+compatibility = ["generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_trade_bindings"
+path = "crates/trade_bindings"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["sdk", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "codegen"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/trade_bindings"
+source_tree_sha256 = "28a60e08d65a891961189d5e614bbc008fe36574b3823333375339c589236342"
+compatibility = ["generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_replica_schema_bindings"
+path = "crates/replica_schema_bindings"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["sdk", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "sdk", "facade", "codegen"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/replica_schema_bindings"
+source_tree_sha256 = "41aeb6520962da64f13e09449d03b6df901b788965732eff439b282fe8f8abb1"
+compatibility = ["generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_event_codec_wasm"
+path = "crates/event_codec_wasm"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["wasm32"]
+groups = ["sdk", "wasm", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "boundary"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/event_codec_wasm"
+source_tree_sha256 = "698abf3b77aa87b6460432342908b475c55bb55d285dc9aef24e27239e4cfa3c"
+compatibility = ["wasm", "generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_replica_store_wasm"
+path = "crates/replica_store_wasm"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["wasm32"]
+groups = ["sdk", "wasm", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "sdk", "facade", "boundary"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/replica_store_wasm"
+source_tree_sha256 = "59cb050d0493047b57aebc4e1bb3adfd5af2fcd464de1f76ffabc1dfabe2baad"
+compatibility = ["wasm", "generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_replica_sync_wasm"
+path = "crates/replica_sync_wasm"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["wasm32"]
+groups = ["sdk", "wasm", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "preview", "sdk", "facade", "boundary"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/replica_sync_wasm"
+source_tree_sha256 = "95f2a291066bab18c744f50a910feecc913dd50a4a3b6c9a464247695d8faffc"
+compatibility = ["wasm", "generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_sdk_ffi"
+path = "crates/sdk_ffi"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["native"]
+groups = ["sdk", "boundaries"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "boundary"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/ffi"
+source_tree_sha256 = "f07e2087f0506b146848476048b32b01584905e2928fe56a36d4f90663590e33"
+compatibility = ["ffi", "generated", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_sdk_sql_wasm_runtime"
+path = "crates/sdk_sql_wasm_runtime"
+state = "reserved_import"
+tier = "adapter"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "MIT OR Apache-2.0"
+platforms = ["wasm32"]
+groups = ["sdk", "wasm"]
+owners = ["sdk"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter"]
+source_repository = "https://github.com/radrootslabs/sdk"
+source_revision = "170ecf2b620107fadca85fcb11fbf3798b4ca1ef"
+source_path = "crates/sql_wasm_runtime"
+source_tree_sha256 = "6ca1dca6f248c50b6bcd4c684b4ad31acd17b8bfc36a8b0072872f6db927c303"
+compatibility = ["wasm", "data", "package_private"]
+removal_gate = "sdk_history_import_verified"
+replaces = []
+
+[[package]]
+name = "radroots_mobile_core"
+path = "crates/mobile_core"
+state = "reserved_import"
+tier = "runtime"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-or-later"
+platforms = ["native", "wasm32"]
+groups = ["mobile"]
+owners = ["mobile"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "runtime"]
+source_repository = "https://github.com/radrootslabs/app_rt"
+source_revision = "7ab1a8624d50890d6d18545ffb47d8083afa8c67"
+source_path = "crates/core"
+source_tree_sha256 = "8ae546ee60a97bfc145c12ea94dcd6d528bf5f49e974159442738c29eb3d6ee1"
+compatibility = ["product", "lifecycle", "package_private"]
+removal_gate = "mobile_history_import_verified"
+replaces = ["radroots_app_core"]
+
+[[package]]
+name = "radroots_mobile_ffi"
+path = "crates/mobile_ffi"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-or-later"
+platforms = ["apple", "android"]
+groups = ["mobile", "boundaries"]
+owners = ["mobile"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "runtime", "boundary"]
+source_repository = "https://github.com/radrootslabs/app_rt"
+source_revision = "7ab1a8624d50890d6d18545ffb47d8083afa8c67"
+source_path = "crates/ffi"
+source_tree_sha256 = "9a38699ad6d39b9f8764fed6a67bd55908ff54cb2e3cae9a3890ce1a46789b2b"
+compatibility = ["ffi", "swift", "kotlin", "lifecycle", "package_private"]
+removal_gate = "mobile_history_import_verified"
+replaces = ["radroots_app_ffi"]
+
+[[package]]
+name = "radroots_mobile_wasm"
+path = "crates/mobile_wasm"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-or-later"
+platforms = ["wasm32"]
+groups = ["mobile", "wasm", "boundaries"]
+owners = ["mobile"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "runtime", "boundary"]
+source_repository = "https://github.com/radrootslabs/app_rt"
+source_revision = "7ab1a8624d50890d6d18545ffb47d8083afa8c67"
+source_path = "crates/wasm"
+source_tree_sha256 = "8c65c867eafc0643ca9fd86150766af4f4ab2f0f8321d66306418261a8f43124"
+compatibility = ["wasm", "lifecycle", "package_private"]
+removal_gate = "mobile_history_import_verified"
+replaces = ["radroots_app_wasm"]
+
+[[package]]
+name = "radroots_mobile_bindgen"
+path = "crates/mobile_bindgen"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-or-later"
+platforms = ["native"]
+groups = ["mobile", "boundaries"]
+owners = ["mobile"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "runtime", "boundary", "codegen"]
+source_repository = "https://github.com/radrootslabs/app_rt"
+source_revision = "7ab1a8624d50890d6d18545ffb47d8083afa8c67"
+source_path = "crates/bindgen"
+source_tree_sha256 = "f0a9d7ec9794257bc56063117208e6e83a34efe1b852e8af6d6a56a1693d27fa"
+compatibility = ["generated", "swift", "kotlin", "package_private"]
+removal_gate = "mobile_history_import_verified"
+replaces = ["radroots_app_bindgen"]
+
+[[package]]
+name = "radroots_studio_domain"
+path = "crates/studio_domain"
+state = "reserved_import"
+tier = "application_domain"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["native"]
+groups = ["studio"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/crates/domain"
+source_tree_sha256 = "25f8abe2f8f4e9dfeb6450116be67eb3faad53f2d3879a4c142796238f74b0a9"
+compatibility = ["product", "data", "package_private"]
+removal_gate = "studio_history_import_verified"
+replaces = ["radroots-studio-domain"]
+
+[[package]]
+name = "radroots_studio_application"
+path = "crates/studio_application"
+state = "reserved_import"
+tier = "application"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["native"]
+groups = ["studio"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain", "application"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/crates/application"
+source_tree_sha256 = "8b0b5d4d74dde0af3c5fb3dac979b0cf57cccf073d597f7bd35b1e73a711fe0b"
+compatibility = ["product", "behavior", "package_private"]
+removal_gate = "studio_history_import_verified"
+replaces = ["radroots-studio-application"]
+
+[[package]]
+name = "radroots_studio_nostr"
+path = "crates/studio_nostr"
+state = "reserved_import"
+tier = "application_adapter"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["native"]
+groups = ["studio"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain", "application", "application_adapter"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/crates/nostr"
+source_tree_sha256 = "2ce5ce0227ab190102a94ffdf80d95b37ed35f5ef62286c4e3e19cd42a777115"
+compatibility = ["network", "security", "package_private"]
+removal_gate = "studio_history_import_verified"
+replaces = ["radroots-studio-nostr"]
+
+[[package]]
+name = "radroots_studio_storage"
+path = "crates/studio_storage"
+state = "reserved_import"
+tier = "application_adapter"
+visibility = "private_adapter"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["native"]
+groups = ["studio"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain", "application", "application_adapter"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/crates/storage"
+source_tree_sha256 = "f3addecbd7f6dbccda4a438597b4e433443a34b48a6c4ef9efa90e49e8f05c4b"
+compatibility = ["data", "keyring", "package_private"]
+removal_gate = "studio_history_import_verified"
+replaces = ["radroots-studio-storage"]
+
+[[package]]
+name = "radroots_studio_runtime"
+path = "crates/studio_runtime"
+state = "reserved_refactor"
+tier = "runtime_composition"
+visibility = "private_runtime"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["native"]
+groups = ["studio"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain", "application", "application_adapter", "runtime_composition"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/crates/ffi"
+source_tree_sha256 = "0bb1d02eb963a606a288d9c35fb418de7bfd914dc5e2c4a38112af64c643151c"
+compatibility = ["product", "lifecycle", "package_private"]
+removal_gate = "studio_runtime_extraction_verified"
+replaces = []
+
+[[package]]
+name = "radroots_studio_ffi"
+path = "crates/studio_ffi"
+state = "reserved_import"
+tier = "boundary"
+visibility = "private_boundary"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["linux", "macos", "windows"]
+groups = ["studio", "boundaries"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain", "application", "application_adapter", "runtime_composition", "boundary"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/crates/ffi"
+source_tree_sha256 = "0bb1d02eb963a606a288d9c35fb418de7bfd914dc5e2c4a38112af64c643151c"
+compatibility = ["ffi", "kotlin", "product", "lifecycle", "package_private"]
+removal_gate = "studio_history_import_verified"
+replaces = ["radroots-studio-ffi"]
+
+[[package]]
+name = "radroots_studio_uniffi_bindgen"
+path = "crates/studio_uniffi_bindgen"
+state = "reserved_import"
+tier = "codegen"
+visibility = "private_codegen"
+publish = false
+version = "0.1.0-alpha"
+license = "GPL-3.0-only"
+platforms = ["native"]
+groups = ["studio", "boundaries"]
+owners = ["studio"]
+permitted_dependency_tiers = ["foundation", "domain", "spi", "adapter", "orchestration", "sdk", "facade", "application_domain", "application", "application_adapter", "runtime_composition", "boundary", "codegen"]
+source_repository = "https://github.com/radrootslabs/studio_app"
+source_revision = "2b5fe5d8321fd0e248a9d304651b1ba54ee6a180"
+source_path = "core/tools/uniffi-bindgen"
+source_tree_sha256 = "0eedd47c17fc7b2b84d953f2c4613aecf96575df466eb106450c7d7eee25ca9b"
+compatibility = ["generated", "kotlin", "package_private"]
+removal_gate = "studio_history_import_verified"
+replaces = ["radroots-studio-uniffi-bindgen"]
diff --git a/contracts/crates/generated/package_groups.v1.toml b/contracts/crates/generated/package_groups.v1.toml
@@ -0,0 +1,38 @@
+schema = "radroots.workspace.package-groups.v1"
+catalog_sha256 = "1a244e2e7f14a20ee21917a246c03277920c927c138796440483bf7837555fcf"
+
+[[group]]
+id = "boundaries"
+packages = ["radroots_core_bindings", "radroots_event_bindings", "radroots_event_codec_wasm", "radroots_identity_bindings", "radroots_mobile_bindgen", "radroots_mobile_ffi", "radroots_mobile_wasm", "radroots_replica_schema_bindings", "radroots_replica_store_wasm", "radroots_replica_sync_wasm", "radroots_sdk_ffi", "radroots_studio_ffi", "radroots_studio_uniffi_bindgen", "radroots_trade_bindings"]
+
+[[group]]
+id = "mobile"
+packages = ["radroots_mobile_bindgen", "radroots_mobile_core", "radroots_mobile_ffi", "radroots_mobile_wasm"]
+
+[[group]]
+id = "portable"
+packages = ["radroots", "radroots_blossom", "radroots_core", "radroots_event", "radroots_event_codec", "radroots_geonames", "radroots_identity", "radroots_nostr", "radroots_nostr_connect", "radroots_protocol", "radroots_sdk", "radroots_secrets", "radroots_signing", "radroots_storage", "radroots_storage_sqlite", "radroots_sync", "radroots_trade", "radroots_transport", "radroots_transport_nostr"]
+
+[[group]]
+id = "preview"
+packages = ["radroots_mesh", "radroots_mesh_agent_client", "radroots_mesh_agent_proto", "radroots_nostrdb", "radroots_replica_schema", "radroots_replica_store", "radroots_replica_sync", "radroots_runtime_distribution", "radroots_runtime_manager", "radroots_runtime_paths", "radroots_simplex_agent_proto", "radroots_simplex_app_store", "radroots_simplex_chat_proto", "radroots_simplex_smp_crypto", "radroots_simplex_smp_proto", "radroots_simplex_smp_transport", "radroots_sql_core", "radroots_test_fixtures", "radroots_transport_reticulum"]
+
+[[group]]
+id = "public_native"
+packages = ["radroots", "radroots_blossom", "radroots_core", "radroots_event", "radroots_event_codec", "radroots_geonames", "radroots_identity", "radroots_nostr", "radroots_nostr_connect", "radroots_protocol", "radroots_sdk", "radroots_secrets", "radroots_signing", "radroots_storage", "radroots_storage_sqlite", "radroots_sync", "radroots_trade", "radroots_transport", "radroots_transport_nostr"]
+
+[[group]]
+id = "sdk"
+packages = ["radroots", "radroots_core_bindings", "radroots_event_bindings", "radroots_event_codec_wasm", "radroots_identity_bindings", "radroots_replica_schema_bindings", "radroots_replica_store_wasm", "radroots_replica_sync_wasm", "radroots_sdk", "radroots_sdk_ffi", "radroots_sdk_sql_wasm_runtime", "radroots_trade_bindings"]
+
+[[group]]
+id = "studio"
+packages = ["radroots_studio_application", "radroots_studio_domain", "radroots_studio_ffi", "radroots_studio_nostr", "radroots_studio_runtime", "radroots_studio_storage", "radroots_studio_uniffi_bindgen"]
+
+[[group]]
+id = "tools"
+packages = ["xtask"]
+
+[[group]]
+id = "wasm"
+packages = ["radroots_event_codec_wasm", "radroots_mobile_wasm", "radroots_replica_store_wasm", "radroots_replica_sync_wasm", "radroots_sdk_sql_wasm_runtime", "radroots_sql_core"]
diff --git a/contracts/crates/generated/platform_inventory.v1.toml b/contracts/crates/generated/platform_inventory.v1.toml
@@ -0,0 +1,34 @@
+schema = "radroots.workspace.platform-inventory.v1"
+catalog_sha256 = "1a244e2e7f14a20ee21917a246c03277920c927c138796440483bf7837555fcf"
+
+[[platform]]
+id = "android"
+packages = ["radroots_mobile_ffi"]
+
+[[platform]]
+id = "any"
+packages = ["radroots", "radroots_blossom", "radroots_core", "radroots_event", "radroots_event_codec", "radroots_identity", "radroots_mesh_agent_proto", "radroots_nostr", "radroots_nostr_connect", "radroots_protocol", "radroots_replica_schema", "radroots_sdk", "radroots_signing", "radroots_simplex_agent_proto", "radroots_simplex_chat_proto", "radroots_simplex_smp_crypto", "radroots_simplex_smp_proto", "radroots_test_fixtures", "radroots_trade", "radroots_transport"]
+
+[[platform]]
+id = "apple"
+packages = ["radroots_mobile_ffi"]
+
+[[platform]]
+id = "linux"
+packages = ["radroots_studio_ffi"]
+
+[[platform]]
+id = "macos"
+packages = ["radroots_studio_ffi"]
+
+[[platform]]
+id = "native"
+packages = ["radroots_core_bindings", "radroots_event_bindings", "radroots_geonames", "radroots_identity_bindings", "radroots_mesh", "radroots_mesh_agent_client", "radroots_mobile_bindgen", "radroots_mobile_core", "radroots_nostrdb", "radroots_replica_schema_bindings", "radroots_replica_store", "radroots_replica_sync", "radroots_runtime_distribution", "radroots_runtime_manager", "radroots_runtime_paths", "radroots_sdk_ffi", "radroots_secrets", "radroots_simplex_app_store", "radroots_simplex_smp_transport", "radroots_sql_core", "radroots_storage", "radroots_storage_sqlite", "radroots_studio_application", "radroots_studio_domain", "radroots_studio_nostr", "radroots_studio_runtime", "radroots_studio_storage", "radroots_studio_uniffi_bindgen", "radroots_sync", "radroots_trade_bindings", "radroots_transport_nostr", "radroots_transport_reticulum", "xtask"]
+
+[[platform]]
+id = "wasm32"
+packages = ["radroots_event_codec_wasm", "radroots_mobile_core", "radroots_mobile_wasm", "radroots_replica_store_wasm", "radroots_replica_sync_wasm", "radroots_sdk_sql_wasm_runtime", "radroots_sql_core"]
+
+[[platform]]
+id = "windows"
+packages = ["radroots_studio_ffi"]
diff --git a/contracts/crates/generated/release_inventory.v2.toml b/contracts/crates/generated/release_inventory.v2.toml
@@ -0,0 +1,7 @@
+schema = "radroots.workspace.release-inventory.v2"
+catalog_sha256 = "1a244e2e7f14a20ee21917a246c03277920c927c138796440483bf7837555fcf"
+architecture = "radroots.crates.release.v2"
+version = "0.1.0-alpha"
+public_packages = ["radroots", "radroots_blossom", "radroots_core", "radroots_event", "radroots_event_codec", "radroots_geonames", "radroots_identity", "radroots_nostr", "radroots_nostr_connect", "radroots_protocol", "radroots_sdk", "radroots_secrets", "radroots_signing", "radroots_storage", "radroots_storage_sqlite", "radroots_sync", "radroots_trade", "radroots_transport", "radroots_transport_nostr"]
+private_packages = ["radroots_core_bindings", "radroots_event_bindings", "radroots_event_codec_wasm", "radroots_identity_bindings", "radroots_mesh", "radroots_mesh_agent_client", "radroots_mesh_agent_proto", "radroots_mobile_bindgen", "radroots_mobile_core", "radroots_mobile_ffi", "radroots_mobile_wasm", "radroots_nostrdb", "radroots_replica_schema", "radroots_replica_schema_bindings", "radroots_replica_store", "radroots_replica_store_wasm", "radroots_replica_sync", "radroots_replica_sync_wasm", "radroots_runtime_distribution", "radroots_runtime_manager", "radroots_runtime_paths", "radroots_sdk_ffi", "radroots_sdk_sql_wasm_runtime", "radroots_simplex_agent_proto", "radroots_simplex_app_store", "radroots_simplex_chat_proto", "radroots_simplex_smp_crypto", "radroots_simplex_smp_proto", "radroots_simplex_smp_transport", "radroots_sql_core", "radroots_studio_application", "radroots_studio_domain", "radroots_studio_ffi", "radroots_studio_nostr", "radroots_studio_runtime", "radroots_studio_storage", "radroots_studio_uniffi_bindgen", "radroots_test_fixtures", "radroots_trade_bindings", "radroots_transport_reticulum", "xtask"]
+reserved_packages = ["radroots", "radroots_core_bindings", "radroots_event_bindings", "radroots_event_codec_wasm", "radroots_identity_bindings", "radroots_mobile_bindgen", "radroots_mobile_core", "radroots_mobile_ffi", "radroots_mobile_wasm", "radroots_replica_schema_bindings", "radroots_replica_store_wasm", "radroots_replica_sync_wasm", "radroots_sdk", "radroots_sdk_ffi", "radroots_sdk_sql_wasm_runtime", "radroots_studio_application", "radroots_studio_domain", "radroots_studio_ffi", "radroots_studio_nostr", "radroots_studio_runtime", "radroots_studio_storage", "radroots_studio_uniffi_bindgen", "radroots_trade_bindings"]
diff --git a/contracts/crates/release.v2.toml b/contracts/crates/release.v2.toml
@@ -0,0 +1,49 @@
+schema_version = 1
+spec_id = "radroots.crates.release.v2"
+status = "approved_not_published"
+supersedes_without_mutation = "radroots.crates.release.v1"
+canonical_repository = "https://github.com/radrootslabs/lib"
+version = "0.1.0-alpha"
+public_package_count = 19
+publication_authorized = false
+public_packages = [
+ "radroots_core",
+ "radroots_identity",
+ "radroots_blossom",
+ "radroots_protocol",
+ "radroots_event",
+ "radroots_event_codec",
+ "radroots_trade",
+ "radroots_signing",
+ "radroots_transport",
+ "radroots_nostr",
+ "radroots_nostr_connect",
+ "radroots_secrets",
+ "radroots_storage",
+ "radroots_storage_sqlite",
+ "radroots_transport_nostr",
+ "radroots_sync",
+ "radroots_geonames",
+ "radroots_sdk",
+ "radroots",
+]
+
+[[v1_artifact]]
+path = "docs/specs/radroots_crates_release_v1.md"
+sha256 = "ea2c1f0f5c53fae56a247ae7519b065c9a0d62dafb998b75a48075f4a875b5eb"
+
+[[v1_artifact]]
+path = "docs/specs/radroots_crates_release_v1.toml"
+sha256 = "1dc18437200dcd65b52090493306f452dade89b5116401d71be4ba4127239b19"
+
+[[v1_artifact]]
+path = "docs/specs/radroots_crates_release_v1_inventory.csv"
+sha256 = "5020875c2cda4b2c9568c8b3f0fad5cd96756c3c779a72481a9652e558f77891"
+
+[[v1_artifact]]
+path = "docs/specs/radroots_crates_release_v1.dot"
+sha256 = "d47de10be596a4d33fee102a4f0617f66700b49515a75a1f42d62c9710043059"
+
+[[v1_artifact]]
+path = "docs/specs/radroots_crates_release_v1.sha256"
+sha256 = "5759ceaae30a9435346320c2791cfda9eb1559b779ea79fd2e94810e14efa281"
diff --git a/tools/xtask/src/catalog.rs b/tools/xtask/src/catalog.rs
@@ -0,0 +1,1063 @@
+use std::{
+ collections::{BTreeMap, BTreeSet},
+ fs,
+ path::{Component, Path},
+ process::Command,
+};
+
+use serde::Deserialize;
+use sha2::{Digest, Sha256};
+
+use crate::contract::artifact_bundle::{
+ GeneratedArtifact, read_regular_file, with_artifact_bundle_transaction,
+};
+
+const CATALOG_RELATIVE: &str = "contracts/crates/catalog.v1.toml";
+const RELEASE_RELATIVE: &str = "contracts/crates/release.v2.toml";
+const CONSOLIDATION_RELATIVE: &str = "contracts/consolidation/architecture.v1.toml";
+const GROUPS_RELATIVE: &str = "contracts/crates/generated/package_groups.v1.toml";
+const PLATFORMS_RELATIVE: &str = "contracts/crates/generated/platform_inventory.v1.toml";
+const RELEASE_INVENTORY_RELATIVE: &str = "contracts/crates/generated/release_inventory.v2.toml";
+const CATALOG_SCHEMA: &str = "radroots.workspace.catalog.v1";
+const RELEASE_ID: &str = "radroots.crates.release.v2";
+const CONSOLIDATION_ID: &str = "radroots.rust.consolidation.v1";
+const VERSION: &str = "0.1.0-alpha";
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct Catalog {
+ schema_version: u16,
+ schema: String,
+ architecture: String,
+ consolidation: String,
+ version: String,
+ rust_version: String,
+ edition: String,
+ resolver: String,
+ public_package_count: usize,
+ package_count: usize,
+ digest_algorithm: String,
+ source_tree_digest_algorithm: String,
+ source_provenance_policy: String,
+ provenance_correction_contract: String,
+ retired_packages: Vec<String>,
+ package: Vec<CatalogPackage>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct CatalogPackage {
+ name: String,
+ path: String,
+ state: String,
+ tier: String,
+ visibility: String,
+ publish: bool,
+ version: String,
+ license: String,
+ platforms: Vec<String>,
+ groups: Vec<String>,
+ owners: Vec<String>,
+ permitted_dependency_tiers: Vec<String>,
+ source_repository: String,
+ source_revision: String,
+ source_path: String,
+ source_tree_sha256: String,
+ compatibility: Vec<String>,
+ removal_gate: Option<String>,
+ replaces: Vec<String>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ReleaseV2 {
+ schema_version: u16,
+ spec_id: String,
+ status: String,
+ supersedes_without_mutation: String,
+ canonical_repository: String,
+ version: String,
+ public_package_count: usize,
+ publication_authorized: bool,
+ public_packages: Vec<String>,
+ v1_artifact: Vec<V1Artifact>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct V1Artifact {
+ path: String,
+ sha256: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ConsolidationV1 {
+ schema_version: u16,
+ consolidation_id: String,
+ architecture: String,
+ canonical_rust_repository: String,
+ donor_repositories: Vec<String>,
+ consumer_repositories: Vec<String>,
+ source_retirement_requires: Vec<String>,
+ repository_archival_requires: Vec<String>,
+}
+
+#[derive(Debug, Deserialize)]
+struct CargoMetadata {
+ packages: Vec<CargoPackage>,
+ workspace_members: Vec<String>,
+}
+
+#[derive(Debug, Deserialize)]
+struct CargoPackage {
+ id: String,
+ name: String,
+ version: String,
+ manifest_path: String,
+ license: Option<String>,
+ publish: Option<Vec<String>>,
+ dependencies: Vec<CargoDependency>,
+}
+
+#[derive(Debug, Deserialize)]
+struct CargoDependency {
+ name: String,
+ req: String,
+ path: Option<String>,
+ kind: Option<String>,
+ target: Option<String>,
+}
+
+pub fn run(args: &[String], workspace_root: &Path) -> Result<(), String> {
+ match args {
+ [command] if command == "check" => check(workspace_root),
+ [command] if command == "write" => write(workspace_root),
+ _ => Err("catalog accepts check or write".to_owned()),
+ }
+}
+
+pub(crate) fn check(workspace_root: &Path) -> Result<(), String> {
+ let loaded = load_and_validate(workspace_root)?;
+ for artifact in render_projections(&loaded.catalog, &loaded.catalog_digest) {
+ let current = read_regular_file(workspace_root, artifact.relative)?;
+ if current != artifact.contents {
+ return Err(format!(
+ "generated catalog projection {} is stale; run catalog write",
+ artifact.relative
+ ));
+ }
+ }
+ Ok(())
+}
+
+fn write(workspace_root: &Path) -> Result<(), String> {
+ let loaded = load_and_validate(workspace_root)?;
+ let artifacts = render_projections(&loaded.catalog, &loaded.catalog_digest);
+ with_artifact_bundle_transaction(workspace_root, |transaction| transaction.write(artifacts))
+}
+
+struct LoadedCatalog {
+ catalog: Catalog,
+ catalog_digest: String,
+}
+
+fn load_and_validate(workspace_root: &Path) -> Result<LoadedCatalog, String> {
+ let catalog_bytes = read_regular_file(workspace_root, CATALOG_RELATIVE)?;
+ let catalog = parse_toml::<Catalog>(CATALOG_RELATIVE, &catalog_bytes)?;
+ let release = parse_file::<ReleaseV2>(workspace_root, RELEASE_RELATIVE)?;
+ let consolidation = parse_file::<ConsolidationV1>(workspace_root, CONSOLIDATION_RELATIVE)?;
+ validate_catalog(&catalog)?;
+ validate_release(&release, &catalog, workspace_root)?;
+ validate_consolidation(&consolidation)?;
+ validate_workspace_manifest(&catalog, workspace_root)?;
+ let metadata = cargo_metadata(workspace_root)?;
+ validate_metadata(&catalog, &metadata, workspace_root)?;
+ validate_active_source_provenance(&catalog, workspace_root)?;
+ Ok(LoadedCatalog {
+ catalog,
+ catalog_digest: sha256(&catalog_bytes),
+ })
+}
+
+fn parse_file<T: for<'de> Deserialize<'de>>(
+ workspace_root: &Path,
+ relative: &str,
+) -> Result<T, String> {
+ let bytes = read_regular_file(workspace_root, relative)?;
+ parse_toml(relative, &bytes)
+}
+
+fn parse_toml<T: for<'de> Deserialize<'de>>(relative: &str, bytes: &[u8]) -> Result<T, String> {
+ let raw =
+ std::str::from_utf8(bytes).map_err(|error| format!("{relative} is not UTF-8: {error}"))?;
+ toml::from_str(raw).map_err(|error| format!("parse {relative}: {error}"))
+}
+
+fn validate_catalog(catalog: &Catalog) -> Result<(), String> {
+ if catalog.schema_version != 1
+ || catalog.schema != CATALOG_SCHEMA
+ || catalog.architecture != RELEASE_ID
+ || catalog.consolidation != CONSOLIDATION_ID
+ || catalog.version != VERSION
+ || catalog.rust_version != "1.97.1"
+ || catalog.edition != "2024"
+ || catalog.resolver != "3"
+ || catalog.public_package_count != 19
+ || catalog.package_count != catalog.package.len()
+ || catalog.digest_algorithm != "sha256-raw-bytes-v1"
+ || catalog.source_tree_digest_algorithm != "sha256-git-ls-tree-r-v1"
+ || catalog.source_provenance_policy != "immutable_after_source_retirement"
+ || catalog.provenance_correction_contract != "approved_correction_record_required"
+ {
+ return Err("catalog identity, toolchain, or cardinality drifted".to_owned());
+ }
+
+ let expected_public = expected_public_packages();
+ let allowed_states = BTreeSet::from(["active", "reserved_import", "reserved_refactor"]);
+ let allowed_visibilities = BTreeSet::from([
+ "public_release",
+ "private_runtime",
+ "private_adapter",
+ "private_boundary",
+ "private_codegen",
+ "private_fixture",
+ "private_tool",
+ ]);
+ let allowed_licenses =
+ BTreeSet::from(["MIT OR Apache-2.0", "GPL-3.0-only", "GPL-3.0-or-later"]);
+ let mut names = BTreeSet::new();
+ let mut paths = BTreeSet::new();
+ let mut public = BTreeSet::new();
+ let mut package_by_name = BTreeMap::new();
+ let mut groups = BTreeSet::new();
+ for package in &catalog.package {
+ validate_identifier(&package.name, "package name")?;
+ validate_relative_path(&package.path)?;
+ validate_identifier(&package.tier, "package tier")?;
+ let expected_path = match package.name.as_str() {
+ "radroots" => "crates/radroots".to_owned(),
+ "xtask" => "tools/xtask".to_owned(),
+ name => format!(
+ "crates/{}",
+ name.strip_prefix("radroots_")
+ .ok_or_else(|| format!("package {name} lacks the radroots_ prefix"))?
+ ),
+ };
+ if package.path != expected_path {
+ return Err(format!(
+ "package {} must use canonical path {expected_path}",
+ package.name
+ ));
+ }
+ if !names.insert(package.name.as_str()) || !paths.insert(package.path.as_str()) {
+ return Err(format!(
+ "duplicate package name or path for {}",
+ package.name
+ ));
+ }
+ if !allowed_states.contains(package.state.as_str())
+ || !allowed_visibilities.contains(package.visibility.as_str())
+ || !allowed_licenses.contains(package.license.as_str())
+ || package.version != VERSION
+ || package.platforms.is_empty()
+ || package.groups.is_empty()
+ || package.owners.is_empty()
+ || package.permitted_dependency_tiers.is_empty()
+ || package.compatibility.is_empty()
+ {
+ return Err(format!("catalog package {} is incomplete", package.name));
+ }
+ validate_unique_identifiers(&package.platforms, "platform")?;
+ validate_unique_identifiers(&package.groups, "group")?;
+ validate_unique_identifiers(&package.owners, "owner")?;
+ validate_unique_identifiers(
+ &package.permitted_dependency_tiers,
+ "permitted dependency tier",
+ )?;
+ validate_unique_identifiers(&package.compatibility, "compatibility authority")?;
+ for group in &package.groups {
+ groups.insert(group.as_str());
+ }
+ if package.visibility == "public_release" {
+ public.insert(package.name.as_str());
+ if !package.publish || package.license != "MIT OR Apache-2.0" {
+ return Err(format!(
+ "public package {} must be permissive and publication-eligible",
+ package.name
+ ));
+ }
+ } else if package.publish {
+ return Err(format!(
+ "private package {} must set publish=false",
+ package.name
+ ));
+ }
+ if package.license.starts_with("GPL-")
+ && !matches!(
+ package.visibility.as_str(),
+ "private_runtime" | "private_adapter" | "private_boundary" | "private_codegen"
+ )
+ {
+ return Err(format!("GPL package {} has an invalid class", package.name));
+ }
+ if package.source_repository
+ != format!(
+ "https://github.com/radrootslabs/{}",
+ source_repository_name(&package.source_repository)?
+ )
+ {
+ return Err(format!(
+ "package {} source repository is noncanonical",
+ package.name
+ ));
+ }
+ validate_oid(&package.source_revision, "source revision")?;
+ validate_relative_path(&package.source_path)?;
+ validate_sha256(&package.source_tree_sha256, "source tree digest")?;
+ for replaced in &package.replaces {
+ validate_package_identity(replaced, "replaced package")?;
+ }
+ if package.state == "active" && package.removal_gate.is_some() {
+ return Err(format!(
+ "active package {} has a removal gate",
+ package.name
+ ));
+ }
+ if package.state != "active"
+ && package
+ .removal_gate
+ .as_deref()
+ .is_none_or(|gate| gate.trim().is_empty())
+ {
+ return Err(format!(
+ "reserved package {} lacks a removal gate",
+ package.name
+ ));
+ }
+ package_by_name.insert(package.name.as_str(), package);
+ }
+ if public != expected_public {
+ return Err("catalog must contain exactly the 19 approved public packages".to_owned());
+ }
+ let required_groups = BTreeSet::from([
+ "boundaries",
+ "mobile",
+ "portable",
+ "preview",
+ "public_native",
+ "sdk",
+ "studio",
+ "tools",
+ "wasm",
+ ]);
+ if !required_groups.is_subset(&groups) {
+ return Err("catalog is missing one or more required package groups".to_owned());
+ }
+ let portable = catalog
+ .package
+ .iter()
+ .filter(|package| package.groups.iter().any(|group| group == "portable"))
+ .map(|package| package.name.as_str())
+ .collect::<BTreeSet<_>>();
+ if portable != expected_public {
+ return Err("portable group must contain exactly the 19 public packages".to_owned());
+ }
+ for package in &catalog.package {
+ for tier in &package.permitted_dependency_tiers {
+ if !catalog
+ .package
+ .iter()
+ .any(|candidate| candidate.tier == *tier)
+ {
+ return Err(format!(
+ "package {} permits unknown tier {tier}",
+ package.name
+ ));
+ }
+ }
+ }
+ let retired = catalog
+ .retired_packages
+ .iter()
+ .map(String::as_str)
+ .collect::<BTreeSet<_>>();
+ if retired.len() != catalog.retired_packages.len()
+ || retired
+ .iter()
+ .any(|name| package_by_name.contains_key(name))
+ || !expected_retired_packages().is_subset(&retired)
+ {
+ return Err("retired package identities are incomplete or reused".to_owned());
+ }
+ let xtasks = catalog
+ .package
+ .iter()
+ .filter(|package| package.name == "xtask")
+ .collect::<Vec<_>>();
+ if xtasks.len() != 1
+ || xtasks[0].path != "tools/xtask"
+ || xtasks[0].visibility != "private_tool"
+ || xtasks[0].state != "active"
+ {
+ return Err("catalog must contain exactly one canonical xtask".to_owned());
+ }
+ Ok(())
+}
+
+fn validate_release(
+ release: &ReleaseV2,
+ catalog: &Catalog,
+ workspace_root: &Path,
+) -> Result<(), String> {
+ if release.schema_version != 1
+ || release.spec_id != RELEASE_ID
+ || release.status != "approved_not_published"
+ || release.supersedes_without_mutation != "radroots.crates.release.v1"
+ || release.canonical_repository != "https://github.com/radrootslabs/lib"
+ || release.version != VERSION
+ || release.public_package_count != 19
+ || release.publication_authorized
+ || release
+ .public_packages
+ .iter()
+ .map(String::as_str)
+ .collect::<BTreeSet<_>>()
+ != expected_public_packages()
+ {
+ return Err("release v2 identity or public allocation drifted".to_owned());
+ }
+ if release.public_packages.len() != release.public_package_count
+ || catalog.public_package_count != release.public_package_count
+ {
+ return Err("release v2 package cardinality drifted".to_owned());
+ }
+ let mut paths = BTreeSet::new();
+ for artifact in &release.v1_artifact {
+ validate_relative_path(&artifact.path)?;
+ validate_sha256(&artifact.sha256, "v1 artifact digest")?;
+ if !paths.insert(artifact.path.as_str()) {
+ return Err("release v2 repeats a v1 artifact".to_owned());
+ }
+ let bytes = read_regular_file(workspace_root, &artifact.path)?;
+ if sha256(&bytes) != artifact.sha256 {
+ return Err(format!("historical v1 artifact {} drifted", artifact.path));
+ }
+ }
+ let expected = BTreeSet::from([
+ "docs/specs/radroots_crates_release_v1.dot",
+ "docs/specs/radroots_crates_release_v1.md",
+ "docs/specs/radroots_crates_release_v1.sha256",
+ "docs/specs/radroots_crates_release_v1.toml",
+ "docs/specs/radroots_crates_release_v1_inventory.csv",
+ ]);
+ if paths != expected {
+ return Err("release v2 must pin every historical v1 authority artifact".to_owned());
+ }
+ Ok(())
+}
+
+fn validate_consolidation(contract: &ConsolidationV1) -> Result<(), String> {
+ if contract.schema_version != 1
+ || contract.consolidation_id != CONSOLIDATION_ID
+ || contract.architecture != RELEASE_ID
+ || contract.canonical_rust_repository != "https://github.com/radrootslabs/lib"
+ || contract
+ .donor_repositories
+ .iter()
+ .map(String::as_str)
+ .collect::<BTreeSet<_>>()
+ != BTreeSet::from([
+ "https://github.com/radrootslabs/app_rt",
+ "https://github.com/radrootslabs/sdk",
+ "https://github.com/radrootslabs/studio_app",
+ ])
+ || contract
+ .consumer_repositories
+ .iter()
+ .map(String::as_str)
+ .collect::<BTreeSet<_>>()
+ != BTreeSet::from([
+ "https://github.com/radrootslabs/sdk",
+ "https://github.com/radrootslabs/studio_app",
+ ])
+ || contract.source_retirement_requires.is_empty()
+ || contract.repository_archival_requires.is_empty()
+ {
+ return Err("consolidation v1 repository authority drifted".to_owned());
+ }
+ validate_unique_identifiers(
+ &contract.source_retirement_requires,
+ "source retirement requirement",
+ )?;
+ validate_unique_identifiers(
+ &contract.repository_archival_requires,
+ "repository archival requirement",
+ )
+}
+
+fn cargo_metadata(workspace_root: &Path) -> Result<CargoMetadata, String> {
+ let output = Command::new("cargo")
+ .args(["metadata", "--format-version", "1", "--locked", "--no-deps"])
+ .current_dir(workspace_root)
+ .output()
+ .map_err(|error| format!("run cargo metadata: {error}"))?;
+ if !output.status.success() {
+ return Err(format!(
+ "cargo metadata failed: {}",
+ String::from_utf8_lossy(&output.stderr).trim()
+ ));
+ }
+ serde_json::from_slice(&output.stdout)
+ .map_err(|error| format!("parse cargo metadata output: {error}"))
+}
+
+fn validate_workspace_manifest(catalog: &Catalog, workspace_root: &Path) -> Result<(), String> {
+ let bytes = read_regular_file(workspace_root, "Cargo.toml")?;
+ let raw =
+ std::str::from_utf8(&bytes).map_err(|error| format!("Cargo.toml is not UTF-8: {error}"))?;
+ let manifest =
+ toml::from_str::<toml::Value>(raw).map_err(|error| format!("parse Cargo.toml: {error}"))?;
+ let workspace = manifest
+ .get("workspace")
+ .and_then(toml::Value::as_table)
+ .ok_or_else(|| "Cargo.toml lacks [workspace]".to_owned())?;
+ let members = workspace
+ .get("members")
+ .and_then(toml::Value::as_array)
+ .ok_or_else(|| "Cargo.toml lacks explicit workspace members".to_owned())?
+ .iter()
+ .map(|value| {
+ value
+ .as_str()
+ .ok_or_else(|| "workspace member must be a string".to_owned())
+ })
+ .collect::<Result<BTreeSet<_>, _>>()?;
+ let active_paths = catalog
+ .package
+ .iter()
+ .filter(|package| package.state == "active")
+ .map(|package| package.path.as_str())
+ .collect::<BTreeSet<_>>();
+ if members != active_paths
+ || members
+ .iter()
+ .any(|member| member.contains('*') || member.contains('?') || member.contains('['))
+ {
+ return Err(
+ "Cargo workspace members must exactly match explicit active catalog paths".to_owned(),
+ );
+ }
+ if workspace.get("resolver").and_then(toml::Value::as_str) != Some("3") {
+ return Err("Cargo workspace resolver must remain 3".to_owned());
+ }
+ let dependencies = manifest
+ .get("workspace")
+ .and_then(|workspace| workspace.get("dependencies"))
+ .and_then(toml::Value::as_table)
+ .ok_or_else(|| "Cargo.toml lacks [workspace.dependencies]".to_owned())?;
+ for package in catalog
+ .package
+ .iter()
+ .filter(|package| package.state == "active" && package.name != "xtask")
+ {
+ let dependency = dependencies
+ .get(&package.name)
+ .and_then(toml::Value::as_table)
+ .ok_or_else(|| format!("workspace dependency {} is missing", package.name))?;
+ if dependency.get("path").and_then(toml::Value::as_str) != Some(package.path.as_str())
+ || dependency.get("version").and_then(toml::Value::as_str)
+ != Some(format!("={VERSION}").as_str())
+ || ["git", "rev", "branch", "tag"]
+ .iter()
+ .any(|key| dependency.contains_key(*key))
+ {
+ return Err(format!(
+ "workspace dependency {} must use its catalog path and exact version only",
+ package.name
+ ));
+ }
+ }
+ Ok(())
+}
+
+fn validate_metadata(
+ catalog: &Catalog,
+ metadata: &CargoMetadata,
+ workspace_root: &Path,
+) -> Result<(), String> {
+ let workspace_ids = metadata
+ .workspace_members
+ .iter()
+ .map(String::as_str)
+ .collect::<BTreeSet<_>>();
+ let workspace_packages = metadata
+ .packages
+ .iter()
+ .filter(|package| workspace_ids.contains(package.id.as_str()))
+ .map(|package| (package.name.as_str(), package))
+ .collect::<BTreeMap<_, _>>();
+ let catalog_by_name = catalog
+ .package
+ .iter()
+ .map(|package| (package.name.as_str(), package))
+ .collect::<BTreeMap<_, _>>();
+ let active = catalog
+ .package
+ .iter()
+ .filter(|package| package.state == "active")
+ .map(|package| package.name.as_str())
+ .collect::<BTreeSet<_>>();
+ if workspace_packages.keys().copied().collect::<BTreeSet<_>>() != active {
+ return Err("active catalog packages and Cargo workspace members differ".to_owned());
+ }
+ for package in catalog
+ .package
+ .iter()
+ .filter(|package| package.state != "active")
+ {
+ if workspace_root.join(&package.path).exists() {
+ return Err(format!(
+ "reserved package path {} exists before its catalog activation",
+ package.path
+ ));
+ }
+ }
+ let canonical_root = fs::canonicalize(workspace_root)
+ .map_err(|error| format!("canonicalize {}: {error}", workspace_root.display()))?;
+ for (name, cargo) in &workspace_packages {
+ let package = catalog_by_name[name];
+ let manifest = Path::new(&cargo.manifest_path);
+ let relative_manifest = manifest
+ .strip_prefix(&canonical_root)
+ .map_err(|_| format!("manifest {} escapes workspace", manifest.display()))?;
+ let actual_path = relative_manifest
+ .parent()
+ .ok_or_else(|| format!("manifest {} has no package root", manifest.display()))?
+ .to_string_lossy()
+ .replace('\\', "/");
+ let cargo_publish = cargo
+ .publish
+ .as_ref()
+ .is_some_and(|registries| !registries.is_empty());
+ if package.path != actual_path
+ || package.version != cargo.version
+ || package.license != cargo.license.as_deref().unwrap_or("")
+ || package.publish != cargo_publish
+ {
+ return Err(format!("catalog and Cargo metadata drifted for {name}"));
+ }
+ for dependency in &cargo.dependencies {
+ let Some(target) = catalog_by_name.get(dependency.name.as_str()) else {
+ continue;
+ };
+ if dependency.path.is_none() || dependency.req != format!("={VERSION}") {
+ return Err(format!(
+ "first-party dependency {name} -> {} must use path plus ={VERSION}",
+ dependency.name
+ ));
+ }
+ if !package
+ .permitted_dependency_tiers
+ .iter()
+ .any(|tier| tier == &target.tier)
+ {
+ return Err(format!(
+ "catalog tier policy forbids {name} -> {} ({:?}, {:?})",
+ dependency.name, dependency.kind, dependency.target
+ ));
+ }
+ if package.visibility == "public_release" && target.visibility != "public_release" {
+ return Err(format!(
+ "public package {name} depends on private package {}",
+ dependency.name
+ ));
+ }
+ if package.license == "MIT OR Apache-2.0" && target.license.starts_with("GPL-") {
+ return Err(format!(
+ "permissive package {name} depends on GPL package {}",
+ dependency.name
+ ));
+ }
+ }
+ }
+ Ok(())
+}
+
+fn validate_active_source_provenance(
+ catalog: &Catalog,
+ workspace_root: &Path,
+) -> Result<(), String> {
+ for package in catalog.package.iter().filter(|package| {
+ package.state == "active"
+ && package.source_repository == "https://github.com/radrootslabs/lib"
+ }) {
+ let output = Command::new("git")
+ .args([
+ "ls-tree",
+ "-r",
+ &package.source_revision,
+ "--",
+ &package.source_path,
+ ])
+ .current_dir(workspace_root)
+ .output()
+ .map_err(|error| format!("run git ls-tree for {}: {error}", package.name))?;
+ if !output.status.success() {
+ return Err(format!(
+ "source revision for {} is unavailable: {}",
+ package.name,
+ String::from_utf8_lossy(&output.stderr).trim()
+ ));
+ }
+ if sha256(&output.stdout) != package.source_tree_sha256 {
+ return Err(format!(
+ "source tree provenance drifted for {}",
+ package.name
+ ));
+ }
+ }
+ Ok(())
+}
+
+fn render_projections(catalog: &Catalog, digest: &str) -> Vec<GeneratedArtifact> {
+ let mut groups = BTreeMap::<&str, Vec<&str>>::new();
+ let mut platforms = BTreeMap::<&str, Vec<&str>>::new();
+ let mut public = Vec::new();
+ let mut private = Vec::new();
+ let mut reserved = Vec::new();
+ for package in &catalog.package {
+ for group in &package.groups {
+ groups.entry(group).or_default().push(&package.name);
+ }
+ for platform in &package.platforms {
+ platforms.entry(platform).or_default().push(&package.name);
+ }
+ if package.visibility == "public_release" {
+ public.push(package.name.as_str());
+ } else {
+ private.push(package.name.as_str());
+ }
+ if package.state != "active" {
+ reserved.push(package.name.as_str());
+ }
+ }
+ sort_map_values(&mut groups);
+ sort_map_values(&mut platforms);
+ public.sort_unstable();
+ private.sort_unstable();
+ reserved.sort_unstable();
+ vec![
+ GeneratedArtifact {
+ relative: GROUPS_RELATIVE,
+ contents: render_map_projection(
+ "radroots.workspace.package-groups.v1",
+ digest,
+ "group",
+ &groups,
+ )
+ .into_bytes(),
+ },
+ GeneratedArtifact {
+ relative: PLATFORMS_RELATIVE,
+ contents: render_map_projection(
+ "radroots.workspace.platform-inventory.v1",
+ digest,
+ "platform",
+ &platforms,
+ )
+ .into_bytes(),
+ },
+ GeneratedArtifact {
+ relative: RELEASE_INVENTORY_RELATIVE,
+ contents: format!(
+ "schema = \"radroots.workspace.release-inventory.v2\"\ncatalog_sha256 = \"{digest}\"\narchitecture = \"{RELEASE_ID}\"\nversion = \"{VERSION}\"\npublic_packages = {}\nprivate_packages = {}\nreserved_packages = {}\n",
+ toml_array(&public),
+ toml_array(&private),
+ toml_array(&reserved)
+ )
+ .into_bytes(),
+ },
+ ]
+}
+
+fn render_map_projection(
+ schema: &str,
+ digest: &str,
+ table: &str,
+ values: &BTreeMap<&str, Vec<&str>>,
+) -> String {
+ let mut output = format!("schema = \"{schema}\"\ncatalog_sha256 = \"{digest}\"\n");
+ for (id, packages) in values {
+ output.push_str(&format!(
+ "\n[[{table}]]\nid = \"{id}\"\npackages = {}\n",
+ toml_array(packages)
+ ));
+ }
+ output
+}
+
+fn toml_array(values: &[&str]) -> String {
+ format!(
+ "[{}]",
+ values
+ .iter()
+ .map(|value| format!("\"{value}\""))
+ .collect::<Vec<_>>()
+ .join(", ")
+ )
+}
+
+fn sort_map_values(values: &mut BTreeMap<&str, Vec<&str>>) {
+ for packages in values.values_mut() {
+ packages.sort_unstable();
+ packages.dedup();
+ }
+}
+
+fn expected_public_packages() -> BTreeSet<&'static str> {
+ BTreeSet::from([
+ "radroots",
+ "radroots_blossom",
+ "radroots_core",
+ "radroots_event",
+ "radroots_event_codec",
+ "radroots_geonames",
+ "radroots_identity",
+ "radroots_nostr",
+ "radroots_nostr_connect",
+ "radroots_protocol",
+ "radroots_sdk",
+ "radroots_secrets",
+ "radroots_signing",
+ "radroots_storage",
+ "radroots_storage_sqlite",
+ "radroots_sync",
+ "radroots_trade",
+ "radroots_transport",
+ "radroots_transport_nostr",
+ ])
+}
+
+fn expected_retired_packages() -> BTreeSet<&'static str> {
+ BTreeSet::from([
+ "radroots-studio-application",
+ "radroots-studio-domain",
+ "radroots-studio-ffi",
+ "radroots-studio-nostr",
+ "radroots-studio-storage",
+ "radroots-studio-uniffi-bindgen",
+ "radroots_app_bindgen",
+ "radroots_app_core",
+ "radroots_app_ffi",
+ "radroots_app_wasm",
+ "radroots_sdk_xtask",
+ ])
+}
+
+fn validate_unique_identifiers(values: &[String], context: &str) -> Result<(), String> {
+ let mut unique = BTreeSet::new();
+ for value in values {
+ validate_identifier(value, context)?;
+ if !unique.insert(value.as_str()) {
+ return Err(format!("duplicate {context} {value}"));
+ }
+ }
+ Ok(())
+}
+
+fn validate_identifier(value: &str, context: &str) -> Result<(), String> {
+ if value.is_empty()
+ || !value
+ .bytes()
+ .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_')
+ {
+ return Err(format!("{context} must use lowercase snake case"));
+ }
+ Ok(())
+}
+
+fn validate_package_identity(value: &str, context: &str) -> Result<(), String> {
+ if value.is_empty()
+ || !value.bytes().all(|byte| {
+ byte.is_ascii_lowercase() || byte.is_ascii_digit() || matches!(byte, b'_' | b'-')
+ })
+ {
+ return Err(format!("{context} is invalid"));
+ }
+ Ok(())
+}
+
+fn validate_relative_path(value: &str) -> Result<(), String> {
+ let path = Path::new(value);
+ if value.is_empty()
+ || path.is_absolute()
+ || value.contains('\\')
+ || value
+ .split('/')
+ .any(|segment| segment.is_empty() || matches!(segment, "." | ".."))
+ || path
+ .components()
+ .any(|component| !matches!(component, Component::Normal(_)))
+ {
+ return Err(format!("catalog path {value:?} is unsafe"));
+ }
+ Ok(())
+}
+
+fn validate_oid(value: &str, context: &str) -> Result<(), String> {
+ if value.len() != 40
+ || !value
+ .bytes()
+ .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
+ {
+ return Err(format!("{context} must be lowercase full 40-hex"));
+ }
+ Ok(())
+}
+
+fn validate_sha256(value: &str, context: &str) -> Result<(), String> {
+ if value.len() != 64
+ || !value
+ .bytes()
+ .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
+ {
+ return Err(format!("{context} must be lowercase 64-hex"));
+ }
+ Ok(())
+}
+
+fn source_repository_name(url: &str) -> Result<&str, String> {
+ url.strip_prefix("https://github.com/radrootslabs/")
+ .filter(|name| {
+ !name.is_empty()
+ && name
+ .bytes()
+ .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_')
+ })
+ .ok_or_else(|| format!("invalid canonical source repository {url}"))
+}
+
+fn sha256(bytes: &[u8]) -> String {
+ format!("{:x}", Sha256::digest(bytes))
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn checked_in_catalog() -> Catalog {
+ parse_file(&crate::workspace_root(), CATALOG_RELATIVE).expect("checked-in catalog")
+ }
+
+ #[test]
+ fn public_inventory_is_exact() {
+ assert_eq!(expected_public_packages().len(), 19);
+ assert!(expected_public_packages().contains("radroots"));
+ assert!(expected_public_packages().contains("radroots_sdk"));
+ }
+
+ #[test]
+ fn paths_and_digests_fail_closed() {
+ assert!(validate_relative_path("crates/sdk").is_ok());
+ assert!(validate_relative_path("../sdk").is_err());
+ assert!(validate_relative_path("crates/./sdk").is_err());
+ assert!(validate_sha256(&"a".repeat(64), "digest").is_ok());
+ assert!(validate_sha256(&"A".repeat(64), "digest").is_err());
+ }
+
+ #[test]
+ fn generated_maps_are_sorted_and_digest_bound() {
+ let mut values = BTreeMap::from([("sdk", vec!["z", "a", "a"])]);
+ sort_map_values(&mut values);
+ let rendered = render_map_projection("fixture.v1", &"a".repeat(64), "group", &values);
+ assert!(rendered.contains("catalog_sha256"));
+ assert!(rendered.contains("packages = [\"a\", \"z\"]"));
+ }
+
+ #[test]
+ fn checked_in_catalog_structure_is_valid() {
+ validate_catalog(&checked_in_catalog()).expect("catalog structure");
+ }
+
+ #[test]
+ fn catalog_rejects_version_visibility_license_and_retirement_drift() {
+ let mut catalog = checked_in_catalog();
+ catalog
+ .package
+ .iter_mut()
+ .find(|package| package.name == "xtask")
+ .expect("xtask")
+ .publish = true;
+ assert!(validate_catalog(&catalog).is_err());
+
+ let mut catalog = checked_in_catalog();
+ catalog
+ .package
+ .iter_mut()
+ .find(|package| package.name == "radroots_core")
+ .expect("core")
+ .license = "GPL-3.0-only".to_owned();
+ assert!(validate_catalog(&catalog).is_err());
+
+ let mut catalog = checked_in_catalog();
+ catalog
+ .package
+ .iter_mut()
+ .find(|package| package.name == "radroots_mobile_core")
+ .expect("mobile")
+ .version = "0.1.0-alpha.1".to_owned();
+ assert!(validate_catalog(&catalog).is_err());
+
+ let mut catalog = checked_in_catalog();
+ catalog.retired_packages.push("radroots_core".to_owned());
+ assert!(validate_catalog(&catalog).is_err());
+ }
+
+ #[test]
+ fn catalog_rejects_naming_path_and_package_count_drift() {
+ let mut catalog = checked_in_catalog();
+ catalog.package_count -= 1;
+ assert!(validate_catalog(&catalog).is_err());
+
+ let mut catalog = checked_in_catalog();
+ catalog.package[0].name = "radroots-bad-name".to_owned();
+ assert!(validate_catalog(&catalog).is_err());
+
+ let mut catalog = checked_in_catalog();
+ catalog.package[0].path = "../escape".to_owned();
+ assert!(validate_catalog(&catalog).is_err());
+ }
+
+ #[test]
+ fn metadata_rejects_floating_sources_and_tier_edges() {
+ let workspace_root = crate::workspace_root();
+ let catalog = checked_in_catalog();
+ let mut metadata = cargo_metadata(&workspace_root).expect("cargo metadata");
+ let dependency = metadata
+ .packages
+ .iter_mut()
+ .find(|package| package.name == "radroots_event")
+ .and_then(|package| {
+ package
+ .dependencies
+ .iter_mut()
+ .find(|dependency| dependency.name == "radroots_core")
+ })
+ .expect("event to core dependency");
+ dependency.path = None;
+ dependency.req = "*".to_owned();
+ assert!(validate_metadata(&catalog, &metadata, &workspace_root).is_err());
+
+ let mut catalog = checked_in_catalog();
+ catalog
+ .package
+ .iter_mut()
+ .find(|package| package.name == "radroots_event")
+ .expect("event")
+ .permitted_dependency_tiers
+ .retain(|tier| tier != "foundation");
+ let metadata = cargo_metadata(&workspace_root).expect("cargo metadata");
+ assert!(validate_metadata(&catalog, &metadata, &workspace_root).is_err());
+ }
+}
diff --git a/tools/xtask/src/contract.rs b/tools/xtask/src/contract.rs
@@ -1,7 +1,7 @@
#![forbid(unsafe_code)]
mod admission_authority;
-mod artifact_bundle;
+pub(crate) mod artifact_bundle;
mod comment_authority;
mod deletion_authority;
mod registry_v7;
diff --git a/tools/xtask/src/contract/artifact_bundle.rs b/tools/xtask/src/contract/artifact_bundle.rs
@@ -14,9 +14,9 @@ const TRANSACTION_DIRECTORY: &str = ".radroots-contract-artifact-transaction-v1"
const TRANSACTION_JOURNAL: &str = "journal.json";
const LOCK_DIRECTORY: &str = "radroots-xtask-contract-artifact-locks-v1";
-pub(super) struct GeneratedArtifact {
- pub(super) relative: &'static str,
- pub(super) contents: Vec<u8>,
+pub(crate) struct GeneratedArtifact {
+ pub(crate) relative: &'static str,
+ pub(crate) contents: Vec<u8>,
}
#[derive(Debug, Deserialize, Serialize)]
@@ -57,17 +57,17 @@ enum SimulatedInterruption {
AfterCommits(usize),
}
-pub(super) struct ArtifactBundleTransaction<'a> {
+pub(crate) struct ArtifactBundleTransaction<'a> {
workspace_root: &'a Path,
}
impl ArtifactBundleTransaction<'_> {
- pub(super) fn write(&self, artifacts: Vec<GeneratedArtifact>) -> Result<(), String> {
+ pub(crate) fn write(&self, artifacts: Vec<GeneratedArtifact>) -> Result<(), String> {
write_artifact_bundle_impl(self.workspace_root, artifacts, None)
}
}
-pub(super) fn read_regular_file(workspace_root: &Path, relative: &str) -> Result<Vec<u8>, String> {
+pub(crate) fn read_regular_file(workspace_root: &Path, relative: &str) -> Result<Vec<u8>, String> {
let path = validate_workspace_path(workspace_root, relative, false)?;
fs::read(path).map_err(|error| format!("read {relative}: {error}"))
}
@@ -99,7 +99,7 @@ pub(super) fn validate_sha256_artifact(relative: &str, bytes: &[u8]) -> Result<(
Ok(())
}
-pub(super) fn with_artifact_bundle_transaction<T>(
+pub(crate) fn with_artifact_bundle_transaction<T>(
workspace_root: &Path,
operation: impl FnOnce(&ArtifactBundleTransaction<'_>) -> Result<T, String>,
) -> Result<T, String> {
diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs
@@ -12,6 +12,8 @@ mod api_qualification;
#[cfg_attr(coverage_nightly, coverage(off))]
mod architecture;
#[cfg_attr(coverage_nightly, coverage(off))]
+mod catalog;
+#[cfg_attr(coverage_nightly, coverage(off))]
mod consolidation;
#[cfg_attr(coverage_nightly, coverage(off))]
mod contract;
@@ -44,6 +46,7 @@ fn usage() {
eprintln!(" cargo xtask architecture-ci");
eprintln!(" cargo xtask check-api-boundaries");
eprintln!(" cargo xtask check-dependency-boundaries");
+ eprintln!(" cargo xtask catalog check|write");
eprintln!(" cargo xtask contract validate");
eprintln!(" cargo xtask contract event-contract-registry-v7 [--write]");
eprintln!(" cargo xtask contract knowledge-manifest [--write]");
@@ -172,6 +175,7 @@ fn run(args: &[String]) -> Result<(), String> {
match args.first().map(String::as_str) {
Some("architecture") if args.len() == 1 => architecture::validate(&workspace_root()),
Some("architecture-ci") if args.len() == 1 => {
+ catalog::check(&workspace_root())?;
architecture::validate_ci(&workspace_root())?;
validate_contract()
}
@@ -181,6 +185,7 @@ fn run(args: &[String]) -> Result<(), String> {
Some("check-dependency-boundaries") if args.len() == 1 => {
architecture::validate_dependency_boundaries(&workspace_root())
}
+ Some("catalog") => catalog::run(&args[1..], &workspace_root()),
Some("contract") => run_contract(&args[1..]),
Some("consolidation") => consolidation::run(&args[1..], &workspace_root()),
Some("coverage") => coverage::run(&args[1..]),