cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit 1e0b18f6d0d0dfe38d694595b928c506694b7af7
parent 4df7efd4631bda46cf932e5fed0e4972b614caaa
Author: triesap <tyson@radroots.org>
Date:   Thu,  9 Jul 2026 08:36:31 +0000

cli: normalize transport status output

- Replace transport and sync status row JSON with configured, implementation, usable_for_delivery, and message fields.
- Remove retired readiness, publish, fetch, and redacted-message output aliases from CLI status DTOs.
- Update terminal rendering and tests for explicit Reticulum preview unavailable delivery status.
- Add source-boundary checks that prevent the removed transport status fields from returning.

Diffstat:
Msrc/out/terminal/renderers/runtime.rs | 12+++++-------
Msrc/runtime/sync.rs | 145++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/runtime/transport.rs | 55++++++++++++++++++++++++++++++++++++++++---------------
Msrc/view/runtime.rs | 20++++++++------------
Mtests/target_cli.rs | 170++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
5 files changed, 278 insertions(+), 124 deletions(-)

diff --git a/src/out/terminal/renderers/runtime.rs b/src/out/terminal/renderers/runtime.rs @@ -188,12 +188,11 @@ fn push_transport_status_table(document: &mut TerminalDocument, result: &Value, TerminalTableRow::new(vec![ common::string(transport, &["transport_kind"]).unwrap_or_default(), common::string(transport, &["profile_id"]).unwrap_or_default(), - common::string(transport, &["implementation_state"]).unwrap_or_default(), - common::string(transport, &["readiness"]).unwrap_or_default(), - common::bool_path(transport, &["publish_usable"]) + common::bool_path(transport, &["configured"]) .map(|value| if value { "yes" } else { "no" }.to_owned()) .unwrap_or_default(), - common::bool_path(transport, &["fetch_usable"]) + common::string(transport, &["implementation"]).unwrap_or_default(), + common::bool_path(transport, &["usable_for_delivery"]) .map(|value| if value { "yes" } else { "no" }.to_owned()) .unwrap_or_default(), common::string(transport, &["endpoint_uri"]).unwrap_or_default(), @@ -205,10 +204,9 @@ fn push_transport_status_table(document: &mut TerminalDocument, result: &Value, vec![ TerminalTableColumn::new("Kind", 4, 12), TerminalTableColumn::new("Profile", 7, 18), + TerminalTableColumn::new("Configured", 10, 10), TerminalTableColumn::new("Implementation", 14, 24), - TerminalTableColumn::new("Readiness", 9, 20), - TerminalTableColumn::new("Publish", 7, 7), - TerminalTableColumn::new("Fetch", 5, 5), + TerminalTableColumn::new("Usable", 6, 6), TerminalTableColumn::new("Endpoint", 8, 32), ], rows, diff --git a/src/runtime/sync.rs b/src/runtime/sync.rs @@ -597,19 +597,28 @@ fn sdk_transport_statuses(receipt: &SyncStatusReceipt) -> Vec<SyncTransportStatu .transport_profile .transport_statuses .iter() - .map(|status| SyncTransportStatusView { - transport_kind: status.transport_kind.clone(), - profile_id: status.profile_id.clone(), - endpoint_uri: status.endpoint_uri.clone(), - implementation_state: status.implementation_state.clone(), - readiness: status.readiness.clone(), - publish_usable: status.publish_usable, - fetch_usable: status.fetch_usable, - redacted_message: status.redacted_message.clone(), - }) + .map(sdk_transport_status_view) .collect() } +fn sdk_transport_status_view( + status: &radroots_sdk::SyncTransportStatusSummary, +) -> SyncTransportStatusView { + SyncTransportStatusView { + transport_kind: status.transport_kind.clone(), + profile_id: status.profile_id.clone(), + endpoint_uri: status.endpoint_uri.clone(), + configured: sync_transport_status_configured(&status.readiness), + implementation: status.implementation_state.clone(), + usable_for_delivery: status.publish_usable, + message: sync_transport_status_message( + &status.transport_kind, + status.publish_usable, + status.redacted_message.as_deref(), + ), + } +} + fn sdk_sync_status_actions(receipt: &SyncStatusReceipt) -> Vec<String> { let mut actions = Vec::new(); if receipt.outbox.ready_signed_events > 0 { @@ -1019,16 +1028,61 @@ fn reticulum_preview_transport_status(profile_id: &str) -> RadrootsTransportStat } fn sync_transport_status_view(status: RadrootsTransportStatus) -> SyncTransportStatusView { + let configured = transport_status_configured(&status); + let usable_for_delivery = status.publish_usable; + let message = transport_status_message(&status); SyncTransportStatusView { transport_kind: status.kind.canonical_label(), profile_id: status.profile_id, endpoint_uri: status.endpoint_uri, - implementation_state: transport_implementation_state_label(status.implementation_state) + configured, + implementation: transport_implementation_state_label(status.implementation_state) .to_owned(), - readiness: transport_readiness_state_label(status.readiness).to_owned(), - publish_usable: status.publish_usable, - fetch_usable: status.fetch_usable, - redacted_message: status.redacted_message, + usable_for_delivery, + message, + } +} + +fn transport_status_configured(status: &RadrootsTransportStatus) -> bool { + matches!( + status.readiness, + RadrootsTransportReadinessState::Ready + | RadrootsTransportReadinessState::PreviewUnavailable + ) +} + +fn sync_transport_status_configured(readiness: &str) -> bool { + matches!(readiness, "ready" | "preview_unavailable") +} + +fn transport_status_message(status: &RadrootsTransportStatus) -> String { + if let Some(message) = &status.redacted_message { + return message.clone(); + } + sync_transport_status_message(&status.kind.canonical_label(), status.publish_usable, None) +} + +fn sync_transport_status_message( + transport_kind: &str, + usable_for_delivery: bool, + redacted_message: Option<&str>, +) -> String { + if let Some(message) = redacted_message { + return message.to_owned(); + } + match transport_kind { + "local" => "Local-only profile writes only to local state".to_owned(), + "nostr" if usable_for_delivery => { + "Nostr relay transport is configured for delivery".to_owned() + } + "nostr" => "Nostr transport requires configured Nostr relay targets".to_owned(), + "reticulum" => RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE.to_owned(), + "mesh" => "Mesh transport status is not available".to_owned(), + "proxy" if usable_for_delivery => { + "Proxy transport delegates delivery to the configured endpoint".to_owned() + } + "proxy" => "Proxy transport requires a configured token file or token secret id".to_owned(), + _ => "Transport status is not available".to_owned(), } } @@ -1043,15 +1097,6 @@ fn transport_implementation_state_label( } } -fn transport_readiness_state_label(state: RadrootsTransportReadinessState) -> &'static str { - match state { - RadrootsTransportReadinessState::Ready => "ready", - RadrootsTransportReadinessState::Disabled => "disabled", - RadrootsTransportReadinessState::Misconfigured => "misconfigured", - RadrootsTransportReadinessState::PreviewUnavailable => "preview_unavailable", - } -} - fn inspect_sync(config: &RuntimeConfig) -> Result<SyncSnapshot, RuntimeError> { let transport_metadata = sync_transport_metadata(config)?; if !config.local.replica_db_path.exists() { @@ -1887,13 +1932,9 @@ mod tests { view.transport_statuses[0].profile_id.as_deref(), Some("nostr") ); - assert_eq!( - view.transport_statuses[0].implementation_state, - "misconfigured" - ); - assert_eq!(view.transport_statuses[0].readiness, "misconfigured"); - assert!(!view.transport_statuses[0].publish_usable); - assert!(!view.transport_statuses[0].fetch_usable); + assert!(!view.transport_statuses[0].configured); + assert_eq!(view.transport_statuses[0].implementation, "misconfigured"); + assert!(!view.transport_statuses[0].usable_for_delivery); assert!(view.target_transport_endpoints.is_empty()); assert_eq!( view.actions, @@ -1925,10 +1966,14 @@ mod tests { ); assert_eq!(view.transport_statuses.len(), 2); assert_eq!(view.transport_statuses[0].transport_kind, "nostr"); - assert!(view.transport_statuses[0].fetch_usable); + assert!(view.transport_statuses[0].usable_for_delivery); assert_eq!(view.transport_statuses[1].transport_kind, "reticulum"); - assert_eq!(view.transport_statuses[1].readiness, "preview_unavailable"); - assert!(!view.transport_statuses[1].fetch_usable); + assert!(view.transport_statuses[1].configured); + assert_eq!( + view.transport_statuses[1].implementation, + "preview_unavailable" + ); + assert!(!view.transport_statuses[1].usable_for_delivery); assert_eq!( view.target_transport_endpoints, vec!["wss://relay.example.com"] @@ -1963,16 +2008,16 @@ mod tests { view.transport_statuses[0].profile_id.as_deref(), Some("hybrid") ); + assert!(!view.transport_statuses[0].configured); + assert_eq!(view.transport_statuses[0].implementation, "misconfigured"); + assert!(!view.transport_statuses[0].usable_for_delivery); + assert_eq!(view.transport_statuses[1].transport_kind, "reticulum"); + assert!(view.transport_statuses[1].configured); assert_eq!( - view.transport_statuses[0].implementation_state, - "misconfigured" + view.transport_statuses[1].implementation, + "preview_unavailable" ); - assert_eq!(view.transport_statuses[0].readiness, "misconfigured"); - assert!(!view.transport_statuses[0].publish_usable); - assert!(!view.transport_statuses[0].fetch_usable); - assert_eq!(view.transport_statuses[1].transport_kind, "reticulum"); - assert_eq!(view.transport_statuses[1].readiness, "preview_unavailable"); - assert!(!view.transport_statuses[1].fetch_usable); + assert!(!view.transport_statuses[1].usable_for_delivery); assert!(view.target_transport_endpoints.is_empty()); assert_eq!(view.actions, vec!["radroots transport profile get"]); } @@ -1991,7 +2036,7 @@ mod tests { assert_eq!(snapshot.transport_statuses.len(), 2); assert_eq!(snapshot.transport_statuses[1].transport_kind, "reticulum"); assert_eq!( - snapshot.transport_statuses[1].readiness, + snapshot.transport_statuses[1].implementation, "preview_unavailable" ); } @@ -2013,7 +2058,12 @@ mod tests { view.configured_transport_targets[0].transport_kind, "reticulum" ); - assert_eq!(view.transport_statuses[0].readiness, "preview_unavailable"); + assert!(view.transport_statuses[0].configured); + assert_eq!( + view.transport_statuses[0].implementation, + "preview_unavailable" + ); + assert!(!view.transport_statuses[0].usable_for_delivery); assert_eq!(view.fetched_count, None); assert!(view.target_transport_endpoints.is_empty()); assert!( @@ -2136,8 +2186,11 @@ mod tests { "reticulum" ); assert_eq!(view.transport_statuses.len(), 2); - assert_eq!(view.transport_statuses[1].readiness, "preview_unavailable"); - assert!(!view.transport_statuses[1].fetch_usable); + assert_eq!( + view.transport_statuses[1].implementation, + "preview_unavailable" + ); + assert!(!view.transport_statuses[1].usable_for_delivery); } #[test] diff --git a/src/runtime/transport.rs b/src/runtime/transport.rs @@ -370,7 +370,7 @@ fn profile_view_from_parts( ); let profile_delivery_usable = transport_statuses .iter() - .any(|status| status.publish_usable); + .any(|status| status.usable_for_delivery); let message = match profile_id { "nostr" if profile_delivery_usable => "Nostr relay transport is configured for delivery", "nostr" => "Nostr transport requires configured Nostr relay targets", @@ -515,16 +515,50 @@ fn proxy_transport_status( } fn transport_runtime_status_view(status: RadrootsTransportStatus) -> TransportRuntimeStatusView { + let configured = transport_status_configured(&status); + let usable_for_delivery = status.publish_usable; + let message = transport_status_message(&status); TransportRuntimeStatusView { transport_kind: status.kind.canonical_label(), profile_id: status.profile_id, endpoint_uri: status.endpoint_uri, - implementation_state: transport_implementation_state_label(status.implementation_state) + configured, + implementation: transport_implementation_state_label(status.implementation_state) .to_owned(), - readiness: transport_readiness_state_label(status.readiness).to_owned(), - publish_usable: status.publish_usable, - fetch_usable: status.fetch_usable, - redacted_message: status.redacted_message, + usable_for_delivery, + message, + } +} + +fn transport_status_configured(status: &RadrootsTransportStatus) -> bool { + matches!( + status.readiness, + RadrootsTransportReadinessState::Ready + | RadrootsTransportReadinessState::PreviewUnavailable + ) +} + +fn transport_status_message(status: &RadrootsTransportStatus) -> String { + if let Some(message) = &status.redacted_message { + return message.clone(); + } + match status.kind { + RadrootsTransportKind::Local => "Local-only profile writes only to local state".to_owned(), + RadrootsTransportKind::Nostr if status.publish_usable => { + "Nostr relay transport is configured for delivery".to_owned() + } + RadrootsTransportKind::Nostr => { + "Nostr transport requires configured Nostr relay targets".to_owned() + } + RadrootsTransportKind::Reticulum => RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE.to_owned(), + RadrootsTransportKind::Mesh => "Mesh transport status is not available".to_owned(), + RadrootsTransportKind::Proxy if status.publish_usable => { + "Proxy transport delegates delivery to the configured endpoint".to_owned() + } + RadrootsTransportKind::Proxy => { + "Proxy transport requires a configured token file or token secret id".to_owned() + } + RadrootsTransportKind::Custom(_) => "Custom transport status is not available".to_owned(), } } @@ -539,15 +573,6 @@ fn transport_implementation_state_label( } } -fn transport_readiness_state_label(state: RadrootsTransportReadinessState) -> &'static str { - match state { - RadrootsTransportReadinessState::Ready => "ready", - RadrootsTransportReadinessState::Disabled => "disabled", - RadrootsTransportReadinessState::Misconfigured => "misconfigured", - RadrootsTransportReadinessState::PreviewUnavailable => "preview_unavailable", - } -} - fn profile_actions(profile_id: &str, profile_delivery_usable: bool) -> Vec<String> { if profile_delivery_usable { return Vec::new(); diff --git a/src/view/runtime.rs b/src/view/runtime.rs @@ -3317,12 +3317,10 @@ pub struct TransportRuntimeStatusView { pub profile_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub endpoint_uri: Option<String>, - pub implementation_state: String, - pub readiness: String, - pub publish_usable: bool, - pub fetch_usable: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub redacted_message: Option<String>, + pub configured: bool, + pub implementation: String, + pub usable_for_delivery: bool, + pub message: String, } #[derive(Debug, Clone, Serialize)] @@ -3558,12 +3556,10 @@ pub struct SyncTransportStatusView { pub profile_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub endpoint_uri: Option<String>, - pub implementation_state: String, - pub readiness: String, - pub publish_usable: bool, - pub fetch_usable: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub redacted_message: Option<String>, + pub configured: bool, + pub implementation: String, + pub usable_for_delivery: bool, + pub message: String, } #[derive(Debug, Clone, Serialize)] diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -91,6 +91,21 @@ fn configure_nostr_transport(sandbox: &RadrootsCliSandbox, relay_url: &str) { sandbox.write_nostr_transport_profile(&[relay_url]); } +fn assert_no_removed_transport_status_fields(status: &Value) { + for field in [ + "implementation_state", + "readiness", + "publish_usable", + "fetch_usable", + "redacted_message", + ] { + assert!( + status.get(field).is_none(), + "{field} must not be serialized" + ); + } +} + fn write_proxy_transport_config(sandbox: &RadrootsCliSandbox, body: &str) -> PathBuf { sandbox.write_app_config( format!("[transport]\nprofile = \"proxy\"\n\n[transport.proxy]\n{body}").as_str(), @@ -1416,15 +1431,19 @@ fn transport_profile_reticulum_preview_output_is_transport_specific() { "reticulum" ); assert_eq!( - result["transport_statuses"][0]["implementation_state"], + result["transport_statuses"][0]["implementation"], "preview_unavailable" ); + assert_eq!(result["transport_statuses"][0]["configured"], true); assert_eq!( - result["transport_statuses"][0]["readiness"], - "preview_unavailable" + result["transport_statuses"][0]["usable_for_delivery"], + false + ); + assert_eq!( + result["transport_statuses"][0]["message"], + RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE ); - assert_eq!(result["transport_statuses"][0]["publish_usable"], false); - assert_eq!(result["transport_statuses"][0]["fetch_usable"], false); + assert_no_removed_transport_status_fields(&result["transport_statuses"][0]); assert_eq!(result["reticulum_preview_behavior"], "defer_delivery_plans"); assert_eq!(result["message"], RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE); assert!( @@ -1463,10 +1482,14 @@ fn transport_profile_local_only_output_uses_profile_and_local_status_fields() { assert_eq!(statuses.len(), 1); assert_eq!(local["transport_kind"], "local"); assert_eq!(local["profile_id"], "local_only"); - assert_eq!(local["implementation_state"], "available"); - assert_eq!(local["readiness"], "ready"); - assert_eq!(local["publish_usable"], false); - assert_eq!(local["fetch_usable"], false); + assert_eq!(local["implementation"], "available"); + assert_eq!(local["configured"], true); + assert_eq!(local["usable_for_delivery"], false); + assert_eq!( + local["message"], + "Local-only profile writes only to local state" + ); + assert_no_removed_transport_status_fields(local); } #[test] @@ -1508,17 +1531,29 @@ fn transport_profile_set_hybrid_persists_nostr_and_reticulum_preview_config() { "nostr" ); assert_eq!( - value["result"]["transport_statuses"][0]["implementation_state"], + value["result"]["transport_statuses"][0]["implementation"], "available" ); + assert_eq!(value["result"]["transport_statuses"][0]["configured"], true); + assert_eq!( + value["result"]["transport_statuses"][0]["usable_for_delivery"], + true + ); assert_eq!( value["result"]["transport_statuses"][1]["transport_kind"], "reticulum" ); assert_eq!( - value["result"]["transport_statuses"][1]["readiness"], + value["result"]["transport_statuses"][1]["implementation"], "preview_unavailable" ); + assert_eq!(value["result"]["transport_statuses"][1]["configured"], true); + assert_eq!( + value["result"]["transport_statuses"][1]["usable_for_delivery"], + false + ); + assert_no_removed_transport_status_fields(&value["result"]["transport_statuses"][0]); + assert_no_removed_transport_status_fields(&value["result"]["transport_statuses"][1]); assert_eq!( value["result"]["reticulum_preview_behavior"], "defer_delivery_plans" @@ -1562,15 +1597,16 @@ fn transport_status_hybrid_output_reports_nostr_and_reticulum_rows() { assert_eq!(result["active_profile"]["profile_delivery_usable"], true); assert_eq!(transports.len(), 2); assert_eq!(nostr["transport_kind"], "nostr"); - assert_eq!(nostr["implementation_state"], "available"); - assert_eq!(nostr["readiness"], "ready"); - assert_eq!(nostr["publish_usable"], true); - assert_eq!(nostr["fetch_usable"], true); + assert_eq!(nostr["implementation"], "available"); + assert_eq!(nostr["configured"], true); + assert_eq!(nostr["usable_for_delivery"], true); assert_eq!(reticulum["transport_kind"], "reticulum"); - assert_eq!(reticulum["implementation_state"], "preview_unavailable"); - assert_eq!(reticulum["readiness"], "preview_unavailable"); - assert_eq!(reticulum["publish_usable"], false); - assert_eq!(reticulum["fetch_usable"], false); + assert_eq!(reticulum["implementation"], "preview_unavailable"); + assert_eq!(reticulum["configured"], true); + assert_eq!(reticulum["usable_for_delivery"], false); + assert_eq!(reticulum["message"], RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE); + assert_no_removed_transport_status_fields(nostr); + assert_no_removed_transport_status_fields(reticulum); } #[test] @@ -1590,10 +1626,10 @@ fn transport_status_nostr_output_uses_canonical_transport_row() { assert_eq!(transports.len(), 1); assert_eq!(nostr["transport_kind"], "nostr"); assert_eq!(nostr["profile_id"], "nostr"); - assert_eq!(nostr["implementation_state"], "available"); - assert_eq!(nostr["readiness"], "ready"); - assert_eq!(nostr["publish_usable"], true); - assert_eq!(nostr["fetch_usable"], true); + assert_eq!(nostr["implementation"], "available"); + assert_eq!(nostr["configured"], true); + assert_eq!(nostr["usable_for_delivery"], true); + assert_no_removed_transport_status_fields(nostr); } #[test] @@ -1618,20 +1654,17 @@ fn transport_status_reticulum_preview_output_reports_unusable_preview_state() { ); assert_eq!(result["active_profile"]["profile_delivery_usable"], false); assert_eq!(active["transport_kind"], "reticulum"); - assert_eq!(active["implementation_state"], "preview_unavailable"); - assert_eq!(active["readiness"], "preview_unavailable"); - assert_eq!(active["publish_usable"], false); - assert_eq!(active["fetch_usable"], false); - assert_eq!( - active["redacted_message"], - RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE - ); + assert_eq!(active["implementation"], "preview_unavailable"); + assert_eq!(active["configured"], true); + assert_eq!(active["usable_for_delivery"], false); + assert_eq!(active["message"], RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE); assert!( - !active["redacted_message"] + !active["message"] .as_str() .expect("message") .contains("Nostr") ); + assert_no_removed_transport_status_fields(active); assert!( !serde_json::to_string(&active["actions"]) .expect("actions json") @@ -1820,6 +1853,8 @@ fn transport_source_boundary_rejects_removed_relay_and_publish_proxy_surfaces() let transport_source = fs::read_to_string(manifest_dir.join("src/runtime/transport.rs")).expect("read source"); + let view_source = + fs::read_to_string(manifest_dir.join("src/view/runtime.rs")).expect("read runtime view"); for required in [ "RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE", "RadrootsTransportStatus::new", @@ -1835,6 +1870,35 @@ fn transport_source_boundary_rejects_removed_relay_and_publish_proxy_surfaces() ); } + let transport_status_view_source = source_window( + view_source.as_str(), + "pub struct TransportRuntimeStatusView", + "pub struct TransportOutboxStatusView", + ); + for required in [ + "pub configured: bool,", + "pub implementation: String,", + "pub usable_for_delivery: bool,", + "pub message: String,", + ] { + assert!( + transport_status_view_source.contains(required), + "transport status view must retain canonical field `{required}`" + ); + } + for forbidden in [ + "pub implementation_state:", + "pub readiness:", + "pub publish_usable:", + "pub fetch_usable:", + "pub redacted_message:", + ] { + assert!( + !transport_status_view_source.contains(forbidden), + "transport status view must not expose removed field `{forbidden}`" + ); + } + let sdk_source = fs::read_to_string(manifest_dir.join("src/runtime/sdk.rs")).expect("read sdk"); for required in [ "pub(crate) fn validate_proxy_bearer_token", @@ -1887,6 +1951,10 @@ fn sync_transport_status_source_boundary_rejects_retired_relay_shaped_generic_ou "pub configured_transport_target_count: usize,", "pub configured_transport_targets: Vec<SyncTransportTargetView>,", "pub transport_statuses: Vec<SyncTransportStatusView>,", + "pub configured: bool,", + "pub implementation: String,", + "pub usable_for_delivery: bool,", + "pub message: String,", "pub target_transport_endpoints: Vec<String>,", "pub attempted_transport_endpoints: Vec<String>,", "pub accepted_transport_endpoints: Vec<String>,", @@ -1898,6 +1966,24 @@ fn sync_transport_status_source_boundary_rejects_retired_relay_shaped_generic_ou ); } + let sync_status_view_source = source_window( + view_source.as_str(), + "pub struct SyncTransportStatusView", + "pub struct TransportTargetFailureView", + ); + for forbidden in [ + "pub implementation_state:", + "pub readiness:", + "pub publish_usable:", + "pub fetch_usable:", + "pub redacted_message:", + ] { + assert!( + !sync_status_view_source.contains(forbidden), + "sync transport status view must not expose removed field `{forbidden}`" + ); + } + for required in [ "fn sdk_sync_status_view", "fn sync_transport_metadata", @@ -2248,17 +2334,15 @@ fn transport_profile_set_proxy_persists_token_file_without_printing_token_materi "proxy" ); assert_eq!( - value["result"]["transport_statuses"][0]["implementation_state"], + value["result"]["transport_statuses"][0]["implementation"], "available" ); + assert_eq!(value["result"]["transport_statuses"][0]["configured"], true); assert_eq!( - value["result"]["transport_statuses"][0]["readiness"], - "ready" - ); - assert_eq!( - value["result"]["transport_statuses"][0]["publish_usable"], + value["result"]["transport_statuses"][0]["usable_for_delivery"], true ); + assert_no_removed_transport_status_fields(&value["result"]["transport_statuses"][0]); assert_eq!(value["result"]["proxy_token_source"], "token_file"); assert_eq!( value["result"]["proxy_token_file"], @@ -2313,17 +2397,15 @@ fn transport_profile_set_proxy_persists_token_secret_id_without_printing_token_m "proxy" ); assert_eq!( - value["result"]["transport_statuses"][0]["implementation_state"], + value["result"]["transport_statuses"][0]["implementation"], "available" ); + assert_eq!(value["result"]["transport_statuses"][0]["configured"], true); assert_eq!( - value["result"]["transport_statuses"][0]["readiness"], - "ready" - ); - assert_eq!( - value["result"]["transport_statuses"][0]["publish_usable"], + value["result"]["transport_statuses"][0]["usable_for_delivery"], true ); + assert_no_removed_transport_status_fields(&value["result"]["transport_statuses"][0]); assert_eq!(value["result"]["proxy_token_source"], "token_secret_id"); assert!(value["result"]["proxy_token_file"].is_null()); assert_eq!(