diagnostics.rs (1944B)
1 //! Redacted client diagnostics composed from canonical capability and storage status. 2 3 /// One passive diagnostics snapshot containing only lower-owned status types. 4 #[derive(Clone, Debug)] 5 pub struct Report { 6 capabilities: crate::capability::CapabilityReport, 7 storage: radroots_storage::StorageStatus, 8 } 9 10 impl Report { 11 /// Returns the side-effect-free SDK capability report. 12 #[must_use] 13 pub const fn capabilities(&self) -> &crate::capability::CapabilityReport { 14 &self.capabilities 15 } 16 17 /// Returns the canonical backend status without implementation details. 18 #[must_use] 19 pub const fn storage(&self) -> radroots_storage::StorageStatus { 20 self.storage 21 } 22 } 23 24 /// Captures passive, secret-safe diagnostics without filesystem paths, SQL, 25 /// connection handles, private artifacts, or recovery side effects. 26 pub async fn inspect(client: &crate::Client) -> crate::Result<Report> { 27 Ok(Report { 28 capabilities: client.capabilities(), 29 storage: client.storage_status().await?, 30 }) 31 } 32 33 #[cfg(all(test, feature = "memory"))] 34 mod tests { 35 use std::sync::Arc; 36 37 use radroots_storage::{ 38 event::SourceGeneration, memory::MemoryStorage, status::StorageBackend, 39 }; 40 41 use crate::ClientBuilder; 42 43 #[tokio::test] 44 async fn report_is_passive_native_and_redacted() { 45 let client = ClientBuilder::new() 46 .storage(Arc::new(MemoryStorage::new( 47 SourceGeneration::new([9; 32]).expect("generation"), 48 ))) 49 .build() 50 .expect("client"); 51 let report = super::inspect(&client).await.expect("report"); 52 53 assert_eq!(report.storage().backend(), StorageBackend::Memory); 54 assert!(report.capabilities().iter().all(|status| { 55 !status.id().as_str().contains('/') && !status.id().as_str().contains('\\') 56 })); 57 assert!(!format!("{report:?}").contains("sqlite")); 58 } 59 }