commit aeda0daab1770993d9741adf93e659c769e53149
parent 0a408fb04b8542b0d9368ea7933bbc6aab7b754e
Author: triesap <tyson@radroots.org>
Date: Sat, 11 Jul 2026 08:10:14 +0000
mesh: derive policy check from mesh model
- add the direct radroots_mesh dependency for preview policy inspection
- report structured mesh policy denial fields from the shared admission model
- render deny reason and compression in terminal mesh policy output
- cover mesh.policy.check JSON output and dependency classification guard updates
Diffstat:
7 files changed, 82 insertions(+), 6 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -3625,6 +3625,7 @@ dependencies = [
"radroots_identity",
"radroots_local_events",
"radroots_log",
+ "radroots_mesh",
"radroots_nostr",
"radroots_nostr_accounts",
"radroots_nostr_connect",
@@ -3752,6 +3753,13 @@ dependencies = [
]
[[package]]
+name = "radroots_mesh"
+version = "0.1.0-alpha.2"
+dependencies = [
+ "radroots_transport",
+]
+
+[[package]]
name = "radroots_nostr"
version = "0.1.0-alpha.2"
dependencies = [
diff --git a/Cargo.toml b/Cargo.toml
@@ -34,6 +34,7 @@ radroots_events_codec = { path = "../lib/crates/events_codec", features = ["nost
radroots_identity = { path = "../lib/crates/identity" }
radroots_local_events = { path = "../lib/crates/local_events" }
radroots_log = { path = "../lib/crates/log" }
+radroots_mesh = { path = "../lib/crates/mesh", default-features = false }
radroots_nostr_accounts = { path = "../lib/crates/nostr_accounts", features = ["os-keyring"] }
radroots_nostr = { path = "../lib/crates/nostr", features = ["client", "events"] }
radroots_nostr_connect = { path = "../lib/crates/nostr_connect" }
diff --git a/src/out/terminal/renderers/runtime.rs b/src/out/terminal/renderers/runtime.rs
@@ -279,6 +279,8 @@ fn mesh_status_document(envelope: &OutputEnvelope, result: &Value) -> TerminalDo
common::push_path_field(&mut document, "Implementation", result, &["implementation"]);
common::push_bool_field(&mut document, "Usable", result, &["usable_for_delivery"]);
common::push_path_field(&mut document, "Decision", result, &["decision"]);
+ common::push_path_field(&mut document, "Deny Reason", result, &["deny_reason"]);
+ common::push_path_field(&mut document, "Compression", result, &["compression"]);
common::push_path_field(&mut document, "Message", result, &["message"]);
document
}
diff --git a/src/runtime/mesh.rs b/src/runtime/mesh.rs
@@ -1,3 +1,7 @@
+use radroots_mesh::{
+ RADROOTS_MESH_PREVIEW_DENIAL_MESSAGE, RadrootsMeshAdmissionInput, RadrootsMeshPayloadPolicy,
+ RadrootsMeshPrivacyClass, RadrootsMeshScope,
+};
use serde_json::Value as JsonValue;
use toml::{Value, map::Map};
@@ -45,21 +49,37 @@ pub fn status(config: &RuntimeConfig) -> MeshStatusView {
configured: scope != "disabled",
implementation: "preview_unavailable".to_owned(),
usable_for_delivery: false,
- message: "Reticulum mesh preview is explicit and unavailable for real delivery".to_owned(),
+ message: RADROOTS_MESH_PREVIEW_DENIAL_MESSAGE.to_owned(),
}
}
pub fn policy_check(config: &RuntimeConfig) -> MeshPolicyCheckView {
+ let policy = RadrootsMeshPayloadPolicy::preview_unavailable();
+ let privacy_class = RadrootsMeshPrivacyClass::PublicEvent;
+ let input = RadrootsMeshAdmissionInput::new(RadrootsMeshScope::Local, privacy_class, 1, 1);
+ let decision = policy.evaluate(&input);
+ let deny_reason = decision
+ .deny_reason()
+ .map(|reason| reason.label())
+ .unwrap_or("none");
+
MeshPolicyCheckView {
state: "ready".to_owned(),
source: MESH_SOURCE.to_owned(),
scope: config.mesh.scope.as_str().to_owned(),
- policy: "reticulum_preview_delivery".to_owned(),
+ policy: policy.policy_id().to_owned(),
transport: "reticulum".to_owned(),
- usable_for_delivery: false,
- decision: "reject_delivery_attempt".to_owned(),
- message: "Reticulum preview never falls back to Nostr and cannot deliver real events"
- .to_owned(),
+ usable_for_delivery: decision.usable_for_delivery(),
+ decision: decision.label().to_owned(),
+ deny_reason: deny_reason.to_owned(),
+ privacy_class: privacy_class.label().to_owned(),
+ payload_bytes: input.payload_bytes,
+ frame_bytes: input.frame_bytes,
+ max_payload_bytes: policy.max_payload_bytes,
+ max_frame_bytes: policy.max_frame_bytes,
+ compression: policy.compression.label().to_owned(),
+ custom_scopes_enabled: policy.custom_scopes_enabled,
+ message: decision.message().to_owned(),
}
}
diff --git a/src/runtime/sdk.rs b/src/runtime/sdk.rs
@@ -870,6 +870,13 @@ mod tests {
},
DirectRrRsDependency {
section: "dependencies",
+ name: "radroots_mesh",
+ owner: "cli-mesh-preview-policy",
+ reason: "canonical Reticulum preview admission policy and structured delivery denial reporting",
+ lifecycle: "retain while CLI exposes mesh preview status and policy inspection",
+ },
+ DirectRrRsDependency {
+ section: "dependencies",
name: "radroots_nostr",
owner: "cli-signer-and-event-runtime",
reason: "remote signer relay transport, account event conversion, and direct publish command transport",
diff --git a/src/view/runtime.rs b/src/view/runtime.rs
@@ -3389,6 +3389,14 @@ pub struct MeshPolicyCheckView {
pub transport: String,
pub usable_for_delivery: bool,
pub decision: String,
+ pub deny_reason: String,
+ pub privacy_class: String,
+ pub payload_bytes: u64,
+ pub frame_bytes: u64,
+ pub max_payload_bytes: u64,
+ pub max_frame_bytes: u64,
+ pub compression: String,
+ pub custom_scopes_enabled: bool,
pub message: String,
}
diff --git a/tests/target_cli.rs b/tests/target_cli.rs
@@ -1827,6 +1827,36 @@ fn mesh_status_reports_reticulum_preview_unusable_state_without_fallback() {
}
#[test]
+fn mesh_policy_check_reports_structured_preview_denial() {
+ let sandbox = RadrootsCliSandbox::new();
+
+ let value = sandbox.json_success(&["--format", "json", "mesh", "policy", "check"]);
+ let result = &value["result"];
+
+ assert_eq!(value["operation_id"], "mesh.policy.check");
+ assert_eq!(result["scope"], "disabled");
+ assert_eq!(result["policy"], "reticulum_preview_delivery");
+ assert_eq!(result["transport"], "reticulum");
+ assert_eq!(result["usable_for_delivery"], false);
+ assert_eq!(result["decision"], "denied");
+ assert_eq!(result["deny_reason"], "preview_unavailable");
+ assert_eq!(result["privacy_class"], "public_event");
+ assert_eq!(result["payload_bytes"], 1);
+ assert_eq!(result["frame_bytes"], 1);
+ assert_eq!(result["max_payload_bytes"], 0);
+ assert_eq!(result["max_frame_bytes"], 0);
+ assert_eq!(result["compression"], "disabled");
+ assert_eq!(result["custom_scopes_enabled"], false);
+ assert_contains(&result["message"], "Reticulum mesh preview is explicit");
+ assert!(
+ !result["message"]
+ .as_str()
+ .expect("message")
+ .contains("Nostr")
+ );
+}
+
+#[test]
fn transport_source_boundary_rejects_removed_relay_and_publish_proxy_surfaces() {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));