lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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 }