lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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:
Acontracts/consolidation/architecture.v1.toml | 28++++++++++++++++++++++++++++
Acontracts/crates/catalog.v1.toml | 1250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontracts/crates/generated/package_groups.v1.toml | 38++++++++++++++++++++++++++++++++++++++
Acontracts/crates/generated/platform_inventory.v1.toml | 34++++++++++++++++++++++++++++++++++
Acontracts/crates/generated/release_inventory.v2.toml | 7+++++++
Acontracts/crates/release.v2.toml | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Atools/xtask/src/catalog.rs | 1063+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/xtask/src/contract.rs | 2+-
Mtools/xtask/src/contract/artifact_bundle.rs | 14+++++++-------
Mtools/xtask/src/main.rs | 5+++++
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..]),