commit 355a7807b9b38afcff7a47750ab09db222310df4
parent 14417d787b2a9216fc32c156972b21f515699f29
Author: triesap <tyson@radroots.org>
Date: Mon, 3 Aug 2026 12:47:12 +0000
facade: implement façade feature forwarding
- Forward the exact client, native, Nostr, NIP-46, daemon, and model features.
- Keep default equal to client and full equal to the governed SDK full bundle.
- Preserve facade exports under full without adding undocumented feature edges.
- Test the exact graph and every supported isolated feature configuration.
Diffstat:
7 files changed, 52 insertions(+), 20 deletions(-)
diff --git a/crates/radroots/Cargo.toml b/crates/radroots/Cargo.toml
@@ -28,11 +28,11 @@ radroots_transport = { workspace = true }
[features]
default = ["client"]
-client = ["radroots_sdk/memory"]
-native = ["client"]
-nostr = ["client"]
-nip46 = ["nostr"]
-radrootsd = ["client"]
-geonames = ["client"]
-knowledge = ["client"]
-full = ["native", "nostr", "nip46", "radrootsd", "geonames", "knowledge"]
+client = ["radroots_sdk/default"]
+native = ["client", "radroots_sdk/native"]
+nostr = ["client", "radroots_sdk/nostr"]
+nip46 = ["nostr", "radroots_sdk/nip46"]
+radrootsd = ["client", "radroots_sdk/radrootsd"]
+geonames = ["client", "radroots_sdk/geonames"]
+knowledge = ["client", "radroots_sdk/knowledge"]
+full = ["radroots_sdk/full"]
diff --git a/crates/radroots/src/client.rs b/crates/radroots/src/client.rs
@@ -1,15 +1,24 @@
//! Curated client construction and operation entry points.
-#[cfg(feature = "nostr")]
+#[cfg(any(feature = "nostr", feature = "full"))]
use std::sync::Arc;
-#[cfg(feature = "nostr")]
+#[cfg(any(feature = "nostr", feature = "full"))]
use radroots_transport::{EventSink, EventSource};
-use crate::{ClientBuilder, transport::Profile};
+#[cfg(any(
+ feature = "client",
+ feature = "native",
+ feature = "nostr",
+ feature = "nip46",
+ feature = "full"
+))]
+use crate::ClientBuilder;
+use crate::transport::Profile;
/// Creates the safe ordinary client builder with deterministic in-process
/// storage and no transport, signer, runtime, worker, or file authority.
+#[cfg(feature = "client")]
#[must_use]
pub fn memory() -> ClientBuilder {
ClientBuilder::memory_default()
@@ -23,7 +32,7 @@ pub const fn local_only() -> Profile {
/// Adds caller-owned source and sink capabilities without connecting them or
/// selecting a fallback transport.
-#[cfg(feature = "nostr")]
+#[cfg(any(feature = "nostr", feature = "full"))]
#[must_use]
pub fn with_transport(
builder: ClientBuilder,
@@ -34,7 +43,7 @@ pub fn with_transport(
}
/// Adds an explicitly constructed NIP-46 signer provider.
-#[cfg(feature = "nip46")]
+#[cfg(any(feature = "nip46", feature = "full"))]
#[must_use]
pub fn with_nip46_signer(
builder: ClientBuilder,
@@ -44,14 +53,14 @@ pub fn with_nip46_signer(
}
/// Explicitly opens validated native SQLite storage.
-#[cfg(feature = "native")]
+#[cfg(any(feature = "native", feature = "full"))]
pub async fn native(options: crate::storage::SqliteOptions) -> crate::Result<ClientBuilder> {
ClientBuilder::sqlite(options).await
}
/// Reports whether the concrete GeoNames capability was selected at compile
/// time. Asset inspection, acquisition, and database opening remain explicit.
-#[cfg(feature = "geonames")]
+#[cfg(any(feature = "geonames", feature = "full"))]
#[must_use]
pub const fn geonames_enabled() -> bool {
true
@@ -59,7 +68,7 @@ pub const fn geonames_enabled() -> bool {
/// Reports whether canonical knowledge contracts were selected at compile
/// time. Merely selecting the feature performs no event or storage operation.
-#[cfg(feature = "knowledge")]
+#[cfg(any(feature = "knowledge", feature = "full"))]
#[must_use]
pub const fn knowledge_enabled() -> bool {
true
diff --git a/crates/radroots/src/knowledge.rs b/crates/radroots/src/knowledge.rs
@@ -1,6 +1,6 @@
//! Curated knowledge-domain entry points.
-#[cfg(feature = "knowledge")]
+#[cfg(any(feature = "knowledge", feature = "full"))]
pub use radroots_event::knowledge::{
AddressableRef, KnowledgeClaim, KnowledgeFieldReport, KnowledgeRelation, KnowledgeReview,
KnowledgeSource, KnowledgeValidationError, WikiArticle, WikiDTagError, WikiMergeRequest,
diff --git a/crates/radroots/src/storage.rs b/crates/radroots/src/storage.rs
@@ -2,5 +2,5 @@
pub use radroots_sdk::storage::{IntegrityStatus, Operations, Status};
-#[cfg(feature = "native")]
+#[cfg(any(feature = "native", feature = "full"))]
pub use radroots_sdk::storage::{SqliteOpenMode, SqliteOptions, SqlitePaths};
diff --git a/crates/radroots/src/transport.rs b/crates/radroots/src/transport.rs
@@ -6,5 +6,5 @@ pub use radroots_transport::{
policy::{SatisfactionClass, SatisfactionPolicy, TargetPolicy},
};
-#[cfg(feature = "radrootsd")]
+#[cfg(any(feature = "radrootsd", feature = "full"))]
pub use radroots_sdk::transport::{DaemonAuth, DaemonConfig, DaemonDelivery, DaemonError};
diff --git a/crates/radroots/tests/package_boundary.rs b/crates/radroots/tests/package_boundary.rs
@@ -25,6 +25,29 @@ fn package_has_final_identity_and_exact_dependencies() {
}
#[test]
+fn features_forward_the_exact_user_oriented_graph() {
+ for forwarding in [
+ "default = [\"client\"]",
+ "client = [\"radroots_sdk/default\"]",
+ "native = [\"client\", \"radroots_sdk/native\"]",
+ "nostr = [\"client\", \"radroots_sdk/nostr\"]",
+ "nip46 = [\"nostr\", \"radroots_sdk/nip46\"]",
+ "radrootsd = [\"client\", \"radroots_sdk/radrootsd\"]",
+ "geonames = [\"client\", \"radroots_sdk/geonames\"]",
+ "knowledge = [\"client\", \"radroots_sdk/knowledge\"]",
+ "full = [\"radroots_sdk/full\"]",
+ ] {
+ assert!(MANIFEST.contains(forwarding), "missing `{forwarding}`");
+ }
+ for forbidden in ["reticulum", "mesh", "simplex", "nostrdb", "replica", "sp1"] {
+ assert!(
+ !MANIFEST.to_ascii_lowercase().contains(forbidden),
+ "forbidden feature vocabulary `{forbidden}`"
+ );
+ }
+}
+
+#[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"));
diff --git a/crates/radroots/tests/public_surface.rs b/crates/radroots/tests/public_surface.rs
@@ -42,7 +42,7 @@ fn ordinary_memory_and_local_only_construction_is_inert() {
assert!(radroots::client::local_only().is_local_only());
}
-#[cfg(feature = "knowledge")]
+#[cfg(any(feature = "knowledge", feature = "full"))]
#[test]
fn canonical_knowledge_paths_compile() {
#[allow(unused_imports)]