commit fd8ac5539de80b0984f754dd072dc7d909671070
parent 2aa953aa7c49a133daaef0407fc1b21074aec399
Author: triesap <tyson@radroots.org>
Date: Thu, 30 Jul 2026 01:54:35 +0000
event-codec: complete package conformance coverage
- execute every knowledge manifest and verified-decode conformance vector
- keep the package fixture byte-identical to its canonical contract corpus
- assert canonical exports, no-std intent, and forbidden host dependency paths
- qualify every feature combination, supported target, doctest, and fuzz target
Diffstat:
3 files changed, 316 insertions(+), 1 deletion(-)
diff --git a/crates/event_codec/tests/fixtures/knowledge_manifest_and_decode.v1.json b/crates/event_codec/tests/fixtures/knowledge_manifest_and_decode.v1.json
@@ -0,0 +1,156 @@
+{
+ "suite": "knowledge_manifest_and_decode",
+ "contract_version": "1.0.0",
+ "vectors": [
+ {
+ "id": "knowledge_manifest_fields_valid_001",
+ "kind": "knowledge.contract_manifest_json.valid",
+ "input": {
+ "registry": "radroots_event_contract_registry_v7"
+ },
+ "expected": {
+ "schema_version": 2,
+ "registry_version": 7,
+ "required_fields": [
+ "schema_version",
+ "registry_version",
+ "radroots_event_version",
+ "radroots_event_codec_version",
+ "contract_id",
+ "kind",
+ "class",
+ "standard",
+ "stability",
+ "privacy",
+ "content_schema",
+ "discriminators",
+ "tag_contracts",
+ "codec_support",
+ "sdk_builder_support",
+ "sdk_draft_support",
+ "wasm_tag_builder_support",
+ "wasm_verified_decode_support",
+ "deprecated",
+ "replaced_by",
+ "introduced_at"
+ ]
+ }
+ },
+ {
+ "id": "knowledge_verify_decode_claim_valid_002",
+ "kind": "knowledge.verify_and_decode_event.valid",
+ "input": {
+ "fixture": "knowledge_claim_valid"
+ },
+ "expected": {
+ "contract_id": "radroots.knowledge.claim.v1",
+ "decoded_variant": "KnowledgeClaim"
+ }
+ },
+ {
+ "id": "knowledge_missing_contract_invalid_003",
+ "kind": "knowledge.verify_and_decode_event.invalid",
+ "input": {
+ "fixture": "missing_contract_id"
+ },
+ "expected": {
+ "error_class": "decode_error",
+ "stage": "contract_validation"
+ }
+ },
+ {
+ "id": "knowledge_nip54_wiki_article_fork_defer_valid_004",
+ "kind": "knowledge.nip54.wiki_article_tags.valid",
+ "input": {
+ "fixture": "wiki_article_valid"
+ },
+ "expected": {
+ "fork_address_tag": [
+ "a",
+ "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health",
+ "wss://relay.example.com",
+ "fork"
+ ],
+ "fork_event_tag": [
+ "e",
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ "wss://relay.example.com",
+ "fork"
+ ],
+ "defer_address_tag": [
+ "a",
+ "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health-v2",
+ "wss://relay.example.com",
+ "defer"
+ ],
+ "defer_event_tag": [
+ "e",
+ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
+ "wss://relay.example.com",
+ "defer"
+ ]
+ }
+ },
+ {
+ "id": "knowledge_nip54_redirect_valid_005",
+ "kind": "knowledge.nip54.wiki_redirect_tags.valid",
+ "input": {
+ "fixture": "wiki_redirect_valid"
+ },
+ "expected": {
+ "target_tag": [
+ "a",
+ "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health",
+ "wss://relay.example.com"
+ ]
+ }
+ },
+ {
+ "id": "knowledge_nip54_merge_request_valid_006",
+ "kind": "knowledge.nip54.wiki_merge_request.valid",
+ "input": {
+ "fixture": "wiki_merge_request_valid"
+ },
+ "expected": {
+ "content": "Merge synthetic soil article updates",
+ "target_tag": [
+ "a",
+ "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health",
+ "wss://relay.example.com"
+ ],
+ "destination_tag": [
+ "p",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ ],
+ "base_event_tag": [
+ "e",
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+ ""
+ ],
+ "source_event_tag": [
+ "e",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "",
+ "source"
+ ]
+ }
+ },
+ {
+ "id": "knowledge_nip54_merge_request_without_base_valid_007",
+ "kind": "knowledge.nip54.wiki_merge_request.valid",
+ "input": {
+ "fixture": "wiki_merge_request_without_base_valid"
+ },
+ "expected": {
+ "content": "Merge synthetic soil article updates",
+ "base_version_event_id": null,
+ "source_event_tag": [
+ "e",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "",
+ "source"
+ ]
+ }
+ }
+ ]
+}
diff --git a/crates/event_codec/tests/knowledge_fixtures.rs b/crates/event_codec/tests/knowledge_fixtures.rs
@@ -27,6 +27,8 @@ use radroots_event_codec::verification::{
RadrootsDecodeError, RadrootsDecodedEvent, RadrootsNip01VerificationError,
verify_and_decode_radroots_event,
};
+#[cfg(feature = "manifests")]
+use radroots_event_codec::{contract_manifest_json, knowledge_contract_manifest};
use radroots_test_fixtures::RELAY_PRIMARY_WSS;
use radroots_test_fixtures::knowledge::{
RADROOTS_KNOWLEDGE_ADVERSARIAL_FIXTURES, RADROOTS_KNOWLEDGE_VALID_CONTRACT_IDS,
@@ -560,3 +562,120 @@ fn verified_decode_exposes_representative_public_surface_events() {
}
}
}
+
+#[cfg(feature = "manifests")]
+#[test]
+fn checked_in_manifest_and_decode_vectors_execute_every_declared_case() {
+ const PACKAGED_VECTORS: &str = include_str!("fixtures/knowledge_manifest_and_decode.v1.json");
+ let workspace_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
+ .join("../../contracts/conformance/vectors/knowledge/manifest_and_decode.v1.json");
+ if let Ok(workspace_vectors) = std::fs::read_to_string(workspace_path) {
+ assert_eq!(PACKAGED_VECTORS, workspace_vectors);
+ }
+
+ let suite: serde_json::Value = serde_json::from_str(PACKAGED_VECTORS).expect("vector suite");
+ assert_eq!(suite["suite"], "knowledge_manifest_and_decode");
+ assert_eq!(suite["contract_version"], "1.0.0");
+ let vectors = suite["vectors"].as_array().expect("vectors");
+ assert_eq!(vectors.len(), 7);
+
+ let fixtures = knowledge_valid_fixtures();
+ for vector in vectors {
+ let id = vector["id"].as_str().expect("vector id");
+ let kind = vector["kind"].as_str().expect("vector kind");
+ let expected = vector["expected"].as_object().expect("expected object");
+ match kind {
+ "knowledge.contract_manifest_json.valid" => {
+ let manifest_json = contract_manifest_json().expect("manifest JSON");
+ let manifest: serde_json::Value =
+ serde_json::from_str(manifest_json.as_str()).expect("manifest value");
+ assert_eq!(
+ manifest["schema_version"], expected["schema_version"],
+ "{id}"
+ );
+ assert_eq!(
+ manifest["registry_version"], expected["registry_version"],
+ "{id}"
+ );
+ let contracts = manifest["contracts"].as_array().expect("contracts");
+ assert_eq!(
+ contracts.len(),
+ knowledge_contract_manifest().contracts.len(),
+ "{id}"
+ );
+ for field in expected["required_fields"]
+ .as_array()
+ .expect("required fields")
+ {
+ let field = field.as_str().expect("field name");
+ assert!(
+ manifest.get(field).is_some()
+ || contracts
+ .iter()
+ .all(|contract| contract.get(field).is_some()),
+ "{id}: missing required manifest field {field}"
+ );
+ }
+ }
+ "knowledge.verify_and_decode_event.valid" => {
+ let fixture_id = vector["input"]["fixture"].as_str().expect("fixture id");
+ let signed = sign_parts(parts_for_fixture(
+ &fixture_by_id(&fixtures, fixture_id).data,
+ ));
+ let decoded = verify_and_decode_radroots_event(signed).expect("decoded event");
+ assert!(
+ matches!(decoded, RadrootsDecodedEvent::KnowledgeClaim(_)),
+ "{id}"
+ );
+ assert_eq!(expected["decoded_variant"], "KnowledgeClaim", "{id}");
+ assert_eq!(
+ expected["contract_id"], RADROOTS_KNOWLEDGE_CLAIM_SCHEMA,
+ "{id}"
+ );
+ }
+ "knowledge.verify_and_decode_event.invalid" => {
+ let mut parts = knowledge_claim_to_wire_parts(&knowledge_claim()).expect("parts");
+ parts
+ .tags
+ .retain(|tag| tag.first().map(String::as_str) != Some("contract"));
+ let error = verify_and_decode_radroots_event(sign_parts(parts))
+ .expect_err("missing contract must fail");
+ assert!(
+ matches!(error, RadrootsDecodeError::ContractValidation(_)),
+ "{id}"
+ );
+ assert_eq!(expected["error_class"], "decode_error", "{id}");
+ assert_eq!(expected["stage"], error.code(), "{id}");
+ }
+ "knowledge.nip54.wiki_article_tags.valid"
+ | "knowledge.nip54.wiki_redirect_tags.valid"
+ | "knowledge.nip54.wiki_merge_request.valid" => {
+ let fixture_id = vector["input"]["fixture"].as_str().expect("fixture id");
+ let parts = parts_for_fixture(&fixture_by_id(&fixtures, fixture_id).data);
+ if let Some(content) = expected.get("content") {
+ assert_eq!(content, parts.content.as_str(), "{id}");
+ }
+ for (field, value) in expected {
+ if field.ends_with("_tag") {
+ let expected_tag = value
+ .as_array()
+ .expect("expected tag")
+ .iter()
+ .map(|value| value.as_str().expect("tag value").to_owned())
+ .collect::<Vec<_>>();
+ assert!(parts.tags.contains(&expected_tag), "{id}: missing {field}");
+ }
+ }
+ if expected.get("base_version_event_id") == Some(&serde_json::Value::Null) {
+ assert!(
+ !parts.tags.iter().any(|tag| {
+ tag == &vec!["e".to_owned(), hex_64('e'), String::new()]
+ }),
+ "{id}: unexpected base event tag"
+ );
+ }
+ }
+ kind => panic!("{id}: unsupported vector kind {kind}"),
+ }
+ }
+}
diff --git a/crates/event_codec/tests/package_boundary.rs b/crates/event_codec/tests/package_boundary.rs
@@ -45,13 +45,53 @@ fn crate_root_declares_every_approved_module() {
}
#[test]
+fn canonical_root_exports_are_explicit_and_host_types_do_not_leak() {
+ for export in [
+ "pub use codec::Codec;",
+ "pub use decode::DecodeError;",
+ "pub use encode::EncodeError;",
+ "pub use verify::VerificationError;",
+ ] {
+ assert!(
+ ROOT.contains(export),
+ "missing canonical root export {export}"
+ );
+ }
+
+ assert!(ROOT.contains("#![cfg_attr(not(feature = \"std\"), no_std)]"));
+ assert!(!ROOT.contains("pub trait "));
+ for forbidden in [
+ "nostr::",
+ "nostr_sdk::",
+ "reqwest::",
+ "sqlx::",
+ "tokio::",
+ "std::os::",
+ ] {
+ assert!(
+ !ROOT.contains(forbidden),
+ "crate root must not expose host path {forbidden}"
+ );
+ }
+}
+
+#[test]
fn codec_runtime_is_protocol_neutral_and_host_free() {
let features = table_keys(MANIFEST, "[features]");
let dependencies = table_keys(MANIFEST, "[dependencies]");
assert!(!features.contains("nostr"));
assert!(dependencies.contains("secp256k1"));
- for forbidden in ["nostr", "nostr-sdk", "reqwest", "sqlx", "tokio"] {
+ for forbidden in [
+ "keyring",
+ "nostr",
+ "nostr-sdk",
+ "reqwest",
+ "sqlx",
+ "tokio",
+ "wasm-bindgen",
+ "web-sys",
+ ] {
assert!(
!dependencies.contains(forbidden),
"codec runtime must not depend on {forbidden}"