sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit e9d7d77cc105113afc209cc80949bcfb93ef4aa9
parent c7211babab84f138ee5569e313b04c6c8281cf8c
Author: triesap <tyson@radroots.org>
Date:   Mon,  6 Jul 2026 01:50:09 +0000

knowledge-sdk: align wiki title optionality

Diffstat:
Mcrates/events_codec_wasm/src/lib.rs | 16+++++++++++++++-
Mcrates/sdk/src/knowledge.rs | 12+++++++-----
Mcrates/sdk/tests/knowledge_public_api.rs | 32+++++++++++++++++++++++++++++++-
Mpackages/events-bindings/src/generated/types.ts | 2+-
4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/crates/events_codec_wasm/src/lib.rs b/crates/events_codec_wasm/src/lib.rs @@ -715,7 +715,7 @@ mod tests { fn sample_wiki_article() -> RadrootsWikiArticle { RadrootsWikiArticle { d_tag: "soil-health".to_string(), - title: "Soil health".to_string(), + title: Some("Soil health".to_string()), content_djot: "# Soil health".to_string(), summary: Some("Living soil basics".to_string()), topics: vec!["soil".to_string()], @@ -1477,6 +1477,20 @@ mod tests { } #[test] + fn wiki_article_tags_accept_missing_title() { + let mut article = sample_wiki_article(); + article.title = None; + let tags = tags_json(wiki_article_tags( + &serde_json::to_string(&article).expect("wiki article json"), + )); + assert!( + !tags + .iter() + .any(|tag| tag.first().map(String::as_str) == Some("title")) + ); + } + + #[test] fn knowledge_claim_tags_enforce_citation_rules() { let mut claim = sample_knowledge_claim(); claim.citation_spans.clear(); diff --git a/crates/sdk/src/knowledge.rs b/crates/sdk/src/knowledge.rs @@ -34,7 +34,7 @@ pub use radroots_events::{ RadrootsKnowledgeSource, RadrootsKnowledgeValidationError, RadrootsRightsAssertion, RadrootsWikiArticle, RadrootsWikiArticleVersionRef, RadrootsWikiDTagError, RadrootsWikiMergeRequest, RadrootsWikiRedirect, normalize_wiki_d_tag, - validate_knowledge_claim, validate_wiki_d_tag, + validate_knowledge_claim, validate_wiki_article, validate_wiki_d_tag, }, }; pub use radroots_events_codec::{ @@ -257,16 +257,18 @@ impl RadrootsWikiArticleBuilder { pub fn build(self) -> Result<RadrootsWikiArticle, RadrootsKnowledgeBuilderError> { validate_builder_wiki_d_tag(&self.d_tag)?; - Ok(RadrootsWikiArticle { + let article = RadrootsWikiArticle { d_tag: self.d_tag, - title: builder_required_string(self.title, "title")?, + title: self.title, content_djot: builder_required_string(self.content_djot, "content_djot")?, summary: self.summary, topics: self.topics, references: self.references, forked_from: self.forked_from, deferred_to: self.deferred_to, - }) + }; + validate_wiki_article(&article).map_err(builder_validation_error)?; + Ok(article) } pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> { @@ -1347,6 +1349,6 @@ pub mod prelude { prepare_knowledge_relation_draft, prepare_knowledge_review_draft, prepare_knowledge_source_draft, prepare_wiki_article_draft, prepare_wiki_merge_request_draft, prepare_wiki_redirect_draft, validate_knowledge_claim, - validate_wiki_d_tag, verify_and_decode_radroots_event, + validate_wiki_article, validate_wiki_d_tag, verify_and_decode_radroots_event, }; } diff --git a/crates/sdk/tests/knowledge_public_api.rs b/crates/sdk/tests/knowledge_public_api.rs @@ -87,6 +87,36 @@ fn fluent_builders_reject_missing_and_invalid_required_fields() { } #[test] +fn wiki_article_builder_accepts_missing_title_but_rejects_blank_title() { + let article = RadrootsWikiArticleBuilder::new("soil-health") + .content_djot("# Soil health") + .build() + .expect("title-free article"); + assert_eq!(article.title, None); + + let parts = RadrootsWikiArticleBuilder::new("soil-health") + .content_djot("# Soil health") + .build_event() + .expect("title-free article parts"); + assert!( + !parts + .tags + .iter() + .any(|tag| tag.first().map(String::as_str) == Some("title")) + ); + + let blank_title = RadrootsWikiArticleBuilder::new("soil-health") + .title(" ") + .content_djot("# Soil health") + .build() + .expect_err("blank title"); + assert_eq!( + blank_title, + RadrootsKnowledgeBuilderError::MissingField("title") + ); +} + +#[test] fn knowledge_claim_builder_enforces_citation_rules() { let missing_citations = RadrootsKnowledgeClaimBuilder::new() .claim_type("practice_effect") @@ -278,7 +308,7 @@ fn address_ref() -> RadrootsAddressableRef { fn wiki_article() -> RadrootsWikiArticle { RadrootsWikiArticle { d_tag: "soil-health".to_owned(), - title: "Soil health".to_owned(), + title: Some("Soil health".to_owned()), content_djot: "# Soil health".to_owned(), summary: Some("Living soil basics".to_owned()), topics: vec!["soil".to_owned(), "local-food".to_owned()], diff --git a/packages/events-bindings/src/generated/types.ts b/packages/events-bindings/src/generated/types.ts @@ -222,7 +222,7 @@ export type RadrootsTradeListingValidateResult = { valid: boolean, errors: Array export type RadrootsTradeValidationListingError = { kind: "invalid_kind", amount: { kind: number, }, } | { kind: "missing_listing_id", } | { kind: "listing_event_not_found", amount: { listing_addr: string, }, } | { kind: "listing_event_fetch_failed", amount: { listing_addr: string, }, } | { kind: "parse_error", amount: { error: RadrootsListingParseError, }, } | { kind: "invalid_seller", } | { kind: "missing_farm_profile", } | { kind: "missing_farm_record", } | { kind: "missing_title", } | { kind: "missing_description", } | { kind: "missing_product_type", } | { kind: "missing_bins", } | { kind: "missing_primary_bin", } | { kind: "invalid_bin", } | { kind: "missing_price", } | { kind: "invalid_price", } | { kind: "missing_inventory", } | { kind: "invalid_inventory", } | { kind: "missing_availability", } | { kind: "missing_location", } | { kind: "missing_location_locality", } | { kind: "missing_location_geohash", } | { kind: "invalid_location_geohash", } | { kind: "missing_delivery_method", }; -export type RadrootsWikiArticle = { d_tag: string, title: string, content_djot: string, summary?: string | null, topics: Array<string>, references: Array<RadrootsNostrEventRef>, forked_from: Array<RadrootsWikiArticleVersionRef>, deferred_to?: RadrootsWikiArticleVersionRef | null, }; +export type RadrootsWikiArticle = { d_tag: string, title?: string | null, content_djot: string, summary?: string | null, topics: Array<string>, references: Array<RadrootsNostrEventRef>, forked_from: Array<RadrootsWikiArticleVersionRef>, deferred_to?: RadrootsWikiArticleVersionRef | null, }; export type RadrootsWikiArticleVersionRef = { event_id: string, address_ref: RadrootsAddressableRef, };