commit 84ec9114bc42376f0fef5b2907b86440a9323ca5
parent 510269bfb468fab87117686ae23ec1ad8d14732a
Author: triesap <tyson@radroots.org>
Date: Mon, 3 Aug 2026 12:33:54 +0000
facade: scaffold the curated façade
- Add the six chartered dependencies with an exact lockstep SDK workspace pin.
- Export only Client, ClientBuilder, Error, and Result from the crate root.
- Validate package identity, dependency inventory, modules, and root API.
- Advance architecture checks from the empty scaffold to the final boundary.
Diffstat:
7 files changed, 132 insertions(+), 5 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1607,6 +1607,14 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "radroots"
version = "0.1.0-alpha"
+dependencies = [
+ "radroots_core",
+ "radroots_event",
+ "radroots_identity",
+ "radroots_sdk",
+ "radroots_trade",
+ "radroots_transport",
+]
[[package]]
name = "radroots_blossom"
diff --git a/Cargo.toml b/Cargo.toml
@@ -80,6 +80,7 @@ radroots_replica_store = { version = "=0.1.0-alpha", default-features = false }
radroots_replica_schema = { version = "=0.1.0-alpha", default-features = false }
radroots_replica_sync = { version = "=0.1.0-alpha", default-features = false }
radroots_runtime_paths = { version = "=0.1.0-alpha", default-features = false }
+radroots_sdk = { path = "crates/sdk", version = "=0.1.0-alpha", default-features = false }
radroots_sdk_sql_wasm_runtime = { path = "crates/sql_wasm_runtime", version = "=0.1.0-alpha" }
radroots_sql_core = { version = "=0.1.0-alpha", default-features = false }
radroots_trade = { package = "radroots_trade", version = "=0.1.0-alpha", default-features = false, features = [
diff --git a/crates/radroots/Cargo.toml b/crates/radroots/Cargo.toml
@@ -18,6 +18,14 @@ workspace = true
name = "radroots"
path = "src/lib.rs"
+[dependencies]
+radroots_core = { workspace = true }
+radroots_event = { workspace = true }
+radroots_identity = { workspace = true }
+radroots_sdk = { workspace = true }
+radroots_trade = { workspace = true }
+radroots_transport = { workspace = true }
+
[features]
default = ["client"]
client = []
diff --git a/crates/radroots/src/lib.rs b/crates/radroots/src/lib.rs
@@ -3,8 +3,8 @@
//! Curated ordinary-user entry point for Radroots.
//!
-//! This non-publishable scaffold reserves the final module and feature
-//! vocabulary without exposing private migration packages.
+//! The root exposes only the ordinary client boundary. Deliberately selected
+//! domain types live in the named modules below.
pub mod client;
pub mod event;
@@ -17,3 +17,5 @@ pub mod storage;
pub mod sync;
pub mod trade;
pub mod transport;
+
+pub use radroots_sdk::{Client, ClientBuilder, Error, Result};
diff --git a/crates/radroots/tests/package_boundary.rs b/crates/radroots/tests/package_boundary.rs
@@ -0,0 +1,46 @@
+use std::collections::BTreeSet;
+
+const MANIFEST: &str = include_str!("../Cargo.toml");
+const WORKSPACE: &str = include_str!("../../../Cargo.toml");
+const ROOT: &str = include_str!("../src/lib.rs");
+
+#[test]
+fn package_has_final_identity_and_exact_dependencies() {
+ assert!(MANIFEST.contains("name = \"radroots\""));
+ assert!(MANIFEST.contains("publish = false"));
+ assert_eq!(
+ dependency_names(MANIFEST),
+ BTreeSet::from([
+ "radroots_core",
+ "radroots_event",
+ "radroots_identity",
+ "radroots_sdk",
+ "radroots_trade",
+ "radroots_transport",
+ ])
+ );
+ assert!(WORKSPACE.contains(
+ "radroots_sdk = { path = \"crates/sdk\", version = \"=0.1.0-alpha\", default-features = false }"
+ ));
+}
+
+#[test]
+fn root_has_exact_exports_and_no_sdk_namespace() {
+ assert!(ROOT.contains("pub use radroots_sdk::{Client, ClientBuilder, Error, Result};"));
+ assert!(!ROOT.contains("pub mod sdk"));
+ assert!(!ROOT.contains("pub use radroots_sdk::*"));
+ assert_eq!(ROOT.matches("pub use ").count(), 1);
+}
+
+fn dependency_names(manifest: &str) -> BTreeSet<&str> {
+ manifest
+ .split_once("[dependencies]")
+ .expect("dependency section")
+ .1
+ .split_once("[features]")
+ .expect("feature section")
+ .0
+ .lines()
+ .filter_map(|line| line.split_once(" = ").map(|(name, _)| name.trim()))
+ .collect()
+}
diff --git a/crates/radroots/tests/public_surface.rs b/crates/radroots/tests/public_surface.rs
@@ -5,3 +5,16 @@ fn approved_module_skeleton_is_public() {
client, event, farm, identity, knowledge, listing, signing, storage, sync, trade, transport,
};
}
+
+#[test]
+fn root_exports_only_the_client_boundary() {
+ fn assert_client<T: Clone + Send + Sync>() {}
+ fn assert_builder<T: Send + Sync>() {}
+ fn assert_error<T: std::error::Error + Send + Sync + 'static>() {}
+
+ assert_client::<radroots::Client>();
+ assert_builder::<radroots::ClientBuilder>();
+ assert_error::<radroots::Error>();
+ let result: radroots::Result<()> = Ok(());
+ assert!(result.is_ok());
+}
diff --git a/tools/xtask/src/check.rs b/tools/xtask/src/check.rs
@@ -224,14 +224,57 @@ fn check_radroots_facade_scaffold(root: &Path) -> Result<(), String> {
{
return Err("radroots facade [lib] must use name radroots and path src/lib.rs".to_owned());
}
- for dependency_table in ["dependencies", "dev-dependencies", "build-dependencies"] {
+ let dependencies = manifest
+ .get("dependencies")
+ .and_then(toml::Value::as_table)
+ .ok_or_else(|| "radroots facade must define [dependencies]".to_owned())?;
+ let actual_dependencies = dependencies
+ .keys()
+ .map(String::as_str)
+ .collect::<BTreeSet<_>>();
+ let expected_dependencies = [
+ "radroots_core",
+ "radroots_event",
+ "radroots_identity",
+ "radroots_sdk",
+ "radroots_trade",
+ "radroots_transport",
+ ]
+ .into_iter()
+ .collect::<BTreeSet<_>>();
+ if actual_dependencies != expected_dependencies {
+ return Err(format!(
+ "radroots facade dependencies must be exactly {}; found {}",
+ expected_dependencies
+ .into_iter()
+ .collect::<Vec<_>>()
+ .join(", "),
+ actual_dependencies
+ .into_iter()
+ .collect::<Vec<_>>()
+ .join(", ")
+ ));
+ }
+ for (name, dependency) in dependencies {
+ if dependency
+ .as_table()
+ .and_then(|value| value.get("workspace"))
+ .and_then(toml::Value::as_bool)
+ != Some(true)
+ {
+ return Err(format!(
+ "radroots facade dependency {name} must inherit the governed workspace entry"
+ ));
+ }
+ }
+ for dependency_table in ["dev-dependencies", "build-dependencies"] {
if manifest
.get(dependency_table)
.and_then(toml::Value::as_table)
.is_some_and(|dependencies| !dependencies.is_empty())
{
return Err(format!(
- "radroots scaffold must not depend on private migration packages through [{dependency_table}]"
+ "radroots facade must not define [{dependency_table}]"
));
}
}
@@ -278,11 +321,17 @@ fn check_radroots_facade_scaffold(root: &Path) -> Result<(), String> {
actual_modules.into_iter().collect::<Vec<_>>().join(", ")
));
}
- if source.contains("pub mod sdk") || source.contains("pub use radroots_sdk") {
+ if source.contains("pub mod sdk") || source.contains("pub use radroots_sdk::*") {
return Err(
"radroots facade must not expose an sdk namespace or broad SDK re-export".to_owned(),
);
}
+ if !source.contains("pub use radroots_sdk::{Client, ClientBuilder, Error, Result};") {
+ return Err(
+ "radroots facade must export exactly the four approved SDK root entry points"
+ .to_owned(),
+ );
+ }
for module in RADROOTS_FACADE_MODULES {
if !root
.join("crates/radroots/src")