knowledge_manifest.rs (9221B)
1 #![cfg(all(feature = "knowledge", feature = "manifests"))] 2 3 mod support; 4 5 use std::collections::BTreeSet; 6 7 use radroots_event::contract::VERSION; 8 use radroots_event::contract::{ 9 EventClass, RADROOTS_EVENT_CONTRACT_REGISTRY_VERSION, all_event_contracts, 10 }; 11 use radroots_event::envelope::kind::{ 12 KIND_CONTRIBUTION_ATTESTATION, KIND_KNOWLEDGE_CHANGE_PROPOSAL, KIND_KNOWLEDGE_CLAIM, 13 KIND_KNOWLEDGE_FIELD_REPORT, KIND_KNOWLEDGE_RELATION, KIND_KNOWLEDGE_REVIEW, 14 }; 15 use radroots_event::knowledge::{ 16 RADROOTS_KNOWLEDGE_CLAIM_SCHEMA, RADROOTS_KNOWLEDGE_FIELD_REPORT_SCHEMA, 17 }; 18 use radroots_event_codec::manifest::{ 19 RADROOTS_KNOWLEDGE_CONTRACT_MANIFEST_SCHEMA_VERSION, RadrootsKnowledgeContractManifest, 20 contract_manifest_json, contract_manifest_sha256, knowledge_contract_manifest, 21 }; 22 use support::knowledge::RADROOTS_KNOWLEDGE_VALID_CONTRACT_IDS; 23 24 const MANIFEST_JSON: &str = include_str!("fixtures/knowledge_event_contract_manifest.v2.json"); 25 const MANIFEST_SHA256: &str = include_str!("fixtures/knowledge_event_contract_manifest.v2.sha256"); 26 const KNOWLEDGE_PUBLIC_SURFACE_VECTOR: &str = 27 include_str!("fixtures/knowledge_public_surface.v1.json"); 28 29 const MVP_SUPPORT_CONTRACT_IDS: &[&str] = &[ 30 "radroots.wiki.article.v1", 31 "radroots.wiki.redirect.v1", 32 "radroots.wiki.merge_request.v1", 33 "radroots.knowledge.source.v1", 34 "radroots.knowledge.claim.v1", 35 "radroots.knowledge.relation.v1", 36 "radroots.knowledge.review.v1", 37 "radroots.knowledge.field_report.v1", 38 ]; 39 40 const BETA_CONTRACT_IDS: &[&str] = &[ 41 "radroots.knowledge.evidence_bounty.v1", 42 "radroots.knowledge.change_proposal.v1", 43 "radroots.knowledge.contribution_attestation.v1", 44 ]; 45 46 #[test] 47 fn knowledge_manifest_is_deterministic_and_matches_artifacts() { 48 let first = contract_manifest_json().unwrap(); 49 let second = contract_manifest_json().unwrap(); 50 assert_eq!(first, second); 51 assert_eq!(first, MANIFEST_JSON); 52 53 let first_hash = contract_manifest_sha256().unwrap(); 54 let second_hash = contract_manifest_sha256().unwrap(); 55 assert_eq!(first_hash, second_hash); 56 assert_eq!(format!("{first_hash}\n"), MANIFEST_SHA256); 57 } 58 59 #[test] 60 fn knowledge_manifest_covers_required_fields_for_every_contract() { 61 let manifest: RadrootsKnowledgeContractManifest = serde_json::from_str(MANIFEST_JSON).unwrap(); 62 assert_eq!( 63 manifest.schema_version, 64 RADROOTS_KNOWLEDGE_CONTRACT_MANIFEST_SCHEMA_VERSION 65 ); 66 assert_eq!( 67 manifest.registry_version, 68 RADROOTS_EVENT_CONTRACT_REGISTRY_VERSION 69 ); 70 assert_eq!(manifest.radroots_event_version, VERSION); 71 assert_eq!( 72 manifest.radroots_event_codec_version, 73 env!("CARGO_PKG_VERSION") 74 ); 75 assert_eq!(manifest.contract_count, manifest.contracts.len()); 76 77 let mut sorted = manifest 78 .contracts 79 .iter() 80 .map(|contract| contract.contract_id.as_str()) 81 .collect::<Vec<_>>(); 82 let original = sorted.clone(); 83 sorted.sort_unstable(); 84 assert_eq!(original, sorted); 85 86 for contract in &manifest.contracts { 87 assert!(!contract.contract_id.trim().is_empty()); 88 assert!(contract.kind > 0); 89 assert!(!contract.class.trim().is_empty()); 90 assert!(!contract.standard.trim().is_empty()); 91 assert_eq!(contract.stability, "experimental"); 92 assert!(!contract.privacy.trim().is_empty()); 93 assert!(!contract.content_schema.trim().is_empty()); 94 assert!(!contract.payload_type.trim().is_empty()); 95 assert!(!contract.discriminators.is_empty()); 96 assert!( 97 !contract.codec_support.verified_decode_requires_nostr 98 || contract.codec_support.verified_decode 99 ); 100 assert!(contract.codec_support.encode); 101 assert!(contract.codec_support.decode); 102 assert!(contract.codec_support.contract_validation); 103 assert!(contract.wasm_verified_decode_support); 104 assert!(!contract.deprecated); 105 assert!(contract.replaced_by.is_none()); 106 assert!(!contract.introduced_at.trim().is_empty()); 107 } 108 109 for contract_id in MVP_SUPPORT_CONTRACT_IDS { 110 let contract = manifest 111 .contracts 112 .iter() 113 .find(|contract| contract.contract_id == *contract_id) 114 .unwrap(); 115 assert!(contract.sdk_builder_support, "{contract_id}"); 116 assert!(contract.sdk_draft_support, "{contract_id}"); 117 assert!(contract.wasm_tag_builder_support, "{contract_id}"); 118 } 119 120 for contract_id in BETA_CONTRACT_IDS { 121 let contract = manifest 122 .contracts 123 .iter() 124 .find(|contract| contract.contract_id == *contract_id) 125 .unwrap(); 126 assert!(!contract.sdk_builder_support, "{contract_id}"); 127 assert!(!contract.sdk_draft_support, "{contract_id}"); 128 assert!(!contract.wasm_tag_builder_support, "{contract_id}"); 129 } 130 131 let merge_request = manifest 132 .contracts 133 .iter() 134 .find(|contract| contract.contract_id == "radroots.wiki.merge_request.v1") 135 .unwrap(); 136 assert_eq!(merge_request.content_schema, "plain_text"); 137 138 let manifest_contracts = manifest 139 .contracts 140 .iter() 141 .map(|contract| contract.contract_id.as_str()) 142 .collect::<BTreeSet<_>>(); 143 let fixture_contracts = RADROOTS_KNOWLEDGE_VALID_CONTRACT_IDS 144 .iter() 145 .copied() 146 .collect::<BTreeSet<_>>(); 147 assert_eq!(manifest_contracts, fixture_contracts); 148 } 149 150 #[test] 151 fn wiki_article_manifest_includes_reference_tag_contracts() { 152 let manifest = knowledge_contract_manifest(); 153 let article = manifest 154 .contracts 155 .iter() 156 .find(|contract| contract.contract_id == "radroots.wiki.article.v1") 157 .unwrap(); 158 159 let expected = [ 160 ("d", "required_one", "identifier", "d_tag", true), 161 ("title", "optional_one", "title", "text", false), 162 ("summary", "optional_one", "summary", "text", false), 163 ( 164 "published_at", 165 "optional_one", 166 "published_at", 167 "unix_timestamp", 168 false, 169 ), 170 ("t", "optional_many", "topic", "text", true), 171 ("source", "optional_many", "source", "event_pointer", false), 172 ( 173 "a", 174 "optional_many", 175 "addressable_coordinate", 176 "addressable_coordinate", 177 true, 178 ), 179 ("e", "optional_many", "event_pointer", "event_id", true), 180 ]; 181 182 assert_eq!(article.tag_contracts.len(), expected.len()); 183 for (name, cardinality, semantic, value_type, relay_indexed) in expected { 184 let tag = article 185 .tag_contracts 186 .iter() 187 .find(|tag| tag.name == name) 188 .unwrap(); 189 assert_eq!(tag.cardinality, cardinality); 190 assert_eq!(tag.semantic, semantic); 191 assert_eq!(tag.value_type, value_type); 192 assert_eq!(tag.relay_indexed, relay_indexed); 193 } 194 } 195 196 #[test] 197 fn knowledge_manifest_preserves_regular_immutable_classification() { 198 let manifest = knowledge_contract_manifest(); 199 for (contract_id, kind) in [ 200 (RADROOTS_KNOWLEDGE_CLAIM_SCHEMA, KIND_KNOWLEDGE_CLAIM), 201 ("radroots.knowledge.relation.v1", KIND_KNOWLEDGE_RELATION), 202 ("radroots.knowledge.review.v1", KIND_KNOWLEDGE_REVIEW), 203 ( 204 RADROOTS_KNOWLEDGE_FIELD_REPORT_SCHEMA, 205 KIND_KNOWLEDGE_FIELD_REPORT, 206 ), 207 ( 208 "radroots.knowledge.change_proposal.v1", 209 KIND_KNOWLEDGE_CHANGE_PROPOSAL, 210 ), 211 ( 212 "radroots.knowledge.contribution_attestation.v1", 213 KIND_CONTRIBUTION_ATTESTATION, 214 ), 215 ] { 216 let manifest_entry = manifest 217 .contracts 218 .iter() 219 .find(|contract| contract.contract_id == contract_id) 220 .unwrap(); 221 let registry_entry = all_event_contracts() 222 .iter() 223 .find(|contract| contract.id == contract_id) 224 .unwrap(); 225 assert_eq!(manifest_entry.kind, kind); 226 assert_eq!(manifest_entry.class, "regular"); 227 assert_eq!(registry_entry.class, EventClass::Regular); 228 } 229 } 230 231 #[test] 232 fn knowledge_manifest_public_surface_vector_stays_generalized() { 233 let value: serde_json::Value = serde_json::from_str(KNOWLEDGE_PUBLIC_SURFACE_VECTOR).unwrap(); 234 assert_eq!(value["suite"], "knowledge_public_surface"); 235 let ids = value["vectors"] 236 .as_array() 237 .unwrap() 238 .iter() 239 .map(|vector| vector["id"].as_str().unwrap()) 240 .collect::<BTreeSet<_>>(); 241 assert_eq!( 242 ids, 243 [ 244 "knowledge_claim_public_surface_valid_002", 245 "knowledge_field_report_public_surface_valid_004", 246 "knowledge_review_public_surface_valid_003", 247 "knowledge_source_public_surface_valid_001", 248 "knowledge_claim_sdk_builder_public_surface_valid_006", 249 "wiki_article_public_surface_valid_005", 250 ] 251 .into_iter() 252 .collect() 253 ); 254 for forbidden in ["dao", "token", "reputation", "score", "canon_synthesis"] { 255 assert!(!KNOWLEDGE_PUBLIC_SURFACE_VECTOR.contains(forbidden)); 256 } 257 }