commit c54d9855bf17af91b1d1040baa5465c45e5b907d
parent a813eec2cb7e5ce8f0b869bb582c130b717c6e9f
Author: triesap <tyson@radroots.org>
Date: Thu, 10 Sep 2026 11:02:43 +0000
calendar: Qualify current shared wire fixtures
- Pin exact current calendar kinds, tags and source-zone fixture provenance
- Check strict signed admission and bounded exclusive UTC day coverage
- Prove real FFI publication, fresh SQLite admission and offline reopen
- Qualify exact generated consumers and complete standalone checks
Diffstat:
12 files changed, 619 insertions(+), 60 deletions(-)
diff --git a/TeraFFI/provenance.json b/TeraFFI/provenance.json
@@ -22,9 +22,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 73868864,
+ "bytes": 73868728,
"path": "TeraFFI.xcframework/ios-arm64-simulator/libtera_ffi.a",
- "sha256": "ed47907bc5ae7835596bf73ab17dad734a82989170c7ed34e491c8465646e528"
+ "sha256": "417da7d44cb3b3e69441673918d22f1aad54ab60c2b57d3f8335999f2ae98967"
},
{
"bytes": 71509,
@@ -37,9 +37,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 73923032,
+ "bytes": 73922992,
"path": "TeraFFI.xcframework/ios-arm64/libtera_ffi.a",
- "sha256": "58d96142e77201061116064e83515aec0ae4ccfcd2e8974b11de4ea3345c43e1"
+ "sha256": "bf6ae1c6d05e1306e715ac40bba50290ceec17ab0dedaf30c8ee491e4f3ada5b"
},
{
"bytes": 42544,
@@ -79,32 +79,32 @@
{
"bytes": 20499440,
"path": "native/aarch64-apple-darwin/libtera_ffi.dylib",
- "sha256": "79f6d1340e4be49e059be5800b247ceaa01307151d188c2739a38e689346abf8"
+ "sha256": "40beed9f054eefec8f87ce75bd3157d74dfdbebbb0b90572ed324bf1aebd49d5"
},
{
- "bytes": 73868864,
+ "bytes": 73868728,
"path": "native/aarch64-apple-ios-sim/libtera_ffi.a",
- "sha256": "ed47907bc5ae7835596bf73ab17dad734a82989170c7ed34e491c8465646e528"
+ "sha256": "417da7d44cb3b3e69441673918d22f1aad54ab60c2b57d3f8335999f2ae98967"
},
{
- "bytes": 73923032,
+ "bytes": 73922992,
"path": "native/aarch64-apple-ios/libtera_ffi.a",
- "sha256": "58d96142e77201061116064e83515aec0ae4ccfcd2e8974b11de4ea3345c43e1"
+ "sha256": "bf6ae1c6d05e1306e715ac40bba50290ceec17ab0dedaf30c8ee491e4f3ada5b"
},
{
- "bytes": 71296,
+ "bytes": 72121,
"path": "source/aarch64-apple-darwin.json",
- "sha256": "42c76082f5a01d21c94d59001b442e04d6ccb4fb428536aaad06988d6b23e938"
+ "sha256": "7a240ff8cdd83a3969f9efa8c94fe87aa702a38670a9cfadc5ceb43134983445"
},
{
- "bytes": 71140,
+ "bytes": 71965,
"path": "source/aarch64-apple-ios-sim.json",
- "sha256": "b72fdce869c7f84db6e627939c3fbaee53077279f68b31eefd0f788d041ae841"
+ "sha256": "717f17889c8f844d0d1d8536e2a0ddf00c4a7e778b33ac55b225ead2a63b4b73"
},
{
- "bytes": 71136,
+ "bytes": 71961,
"path": "source/aarch64-apple-ios.json",
- "sha256": "ffa229ef3fd7e745364d59c5284a68111d0be1c7981a2b465f2b4d225d833fc0"
+ "sha256": "980c41d31200d854315d597cf3ee01b1592ba39f8badf9bf3651895bd784246b"
}
],
"language": "swift",
@@ -112,7 +112,7 @@
"schema": "radroots.artifact-manifest.v2",
"source": {
"repository": "https://github.com/radrootslabs/tera",
- "tree": "d66c73094f8b59dc2e016029720be10ebc5ada91"
+ "tree": "2cd97ed5ace482fe1d1836445bc74cd39f4107bc"
},
"source_records": {
"aarch64-apple-darwin": "source/aarch64-apple-darwin.json",
@@ -139,9 +139,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 73868864,
+ "bytes": 73868728,
"path": "Tera/Frameworks/TeraFFI.xcframework/ios-arm64-simulator/libtera_ffi.a",
- "sha256": "ed47907bc5ae7835596bf73ab17dad734a82989170c7ed34e491c8465646e528"
+ "sha256": "417da7d44cb3b3e69441673918d22f1aad54ab60c2b57d3f8335999f2ae98967"
},
{
"bytes": 71509,
@@ -154,9 +154,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 73923032,
+ "bytes": 73922992,
"path": "Tera/Frameworks/TeraFFI.xcframework/ios-arm64/libtera_ffi.a",
- "sha256": "58d96142e77201061116064e83515aec0ae4ccfcd2e8974b11de4ea3345c43e1"
+ "sha256": "bf6ae1c6d05e1306e715ac40bba50290ceec17ab0dedaf30c8ee491e4f3ada5b"
},
{
"bytes": 521598,
@@ -174,19 +174,19 @@
"sha256": "e2e025ee9a29182970f52f53593796afd154cdfb09aba197474577103dcb4ad6"
},
{
- "bytes": 71296,
+ "bytes": 72121,
"path": "TeraFFI/source/aarch64-apple-darwin.json",
- "sha256": "42c76082f5a01d21c94d59001b442e04d6ccb4fb428536aaad06988d6b23e938"
+ "sha256": "7a240ff8cdd83a3969f9efa8c94fe87aa702a38670a9cfadc5ceb43134983445"
},
{
- "bytes": 71140,
+ "bytes": 71965,
"path": "TeraFFI/source/aarch64-apple-ios-sim.json",
- "sha256": "b72fdce869c7f84db6e627939c3fbaee53077279f68b31eefd0f788d041ae841"
+ "sha256": "717f17889c8f844d0d1d8536e2a0ddf00c4a7e778b33ac55b225ead2a63b4b73"
},
{
- "bytes": 71136,
+ "bytes": 71961,
"path": "TeraFFI/source/aarch64-apple-ios.json",
- "sha256": "ffa229ef3fd7e745364d59c5284a68111d0be1c7981a2b465f2b4d225d833fc0"
+ "sha256": "980c41d31200d854315d597cf3ee01b1592ba39f8badf9bf3651895bd784246b"
}
],
"schema": "tera.installed-native-artifacts.v1"
diff --git a/TeraFFI/source.lock b/TeraFFI/source.lock
@@ -1,7 +1,7 @@
schema = "tera.installed-source.v1"
repository = "https://github.com/radrootslabs/tera"
-source_tree = "d66c73094f8b59dc2e016029720be10ebc5ada91"
-manifest_sha256 = "33eda17ee164b8ec3d38df3586d4336249ad1ed13a65a88467e75888bb7347be"
+source_tree = "2cd97ed5ace482fe1d1836445bc74cd39f4107bc"
+manifest_sha256 = "1cc7fd2b6773c7d407e06d715d12bb7923b2e8055e473fdecf251f77c06d332c"
source_date_epoch = 1787871027
[foundation]
diff --git a/TeraFFI/source/aarch64-apple-darwin.json b/TeraFFI/source/aarch64-apple-darwin.json
@@ -668,6 +668,12 @@
"mode": "100644",
"sha256": "79fd90c240c67137232e6278e69f87a2159b6e078eb99123823a4fc11ce8fcc8"
},
+ "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs": {
+ "bytes": 9425,
+ "git_blob": "da908dfacbeb6fff82bc618ba4d5e7ec9aa9e6a9",
+ "mode": "100644",
+ "sha256": "3ec65d1cb2d94740396137d03920b212afb74692dba11729e4ce5bb3c5a2a789"
+ },
"core/crates/tera_core/src/runtime/product_surface/context.rs": {
"bytes": 14211,
"git_blob": "92498807101c638cec675e0b49fde1f4ceed17a2",
@@ -747,10 +753,10 @@
"sha256": "76e3bddfc237dac63293d264d68991b489585136fe377e39dbba72aa3a1181f4"
},
"core/crates/tera_core/src/runtime/product_surface/today.rs": {
- "bytes": 140839,
- "git_blob": "2ac582261824b8127a5b12e1effccbc56e3e4e42",
+ "bytes": 140913,
+ "git_blob": "cdbd64d61b33c2e35b4adcbe41834125286caa78",
"mode": "100644",
- "sha256": "ed24b32ba9c956af9723c251eb25fa7a726ea19844392c770b5363352c9fdb62"
+ "sha256": "4ef107bd6e4dd7870fd262dea9efebcc19ed7e6b262a9baa34ebdf8894d2720c"
},
"core/crates/tera_core/src/runtime/product_surface/today_admission_tests.rs": {
"bytes": 14718,
@@ -1046,11 +1052,17 @@
"mode": "100644",
"sha256": "4cb6aa1ff8b006d8a8710e807c9965d47fdd3e72eca67b28a5d909696574f161"
},
+ "core/crates/tera_ffi/tests/local_mvp/calendar_wire_runtime.rs": {
+ "bytes": 6876,
+ "git_blob": "2ba8bf12c3449ac8b73604c5199badf041feac6b",
+ "mode": "100644",
+ "sha256": "7b86747a88a0406f5aac3a8dd753bdafb5e955ac51caf614bd1dee2e90beb50b"
+ },
"core/crates/tera_ffi/tests/local_mvp_real_io.rs": {
- "bytes": 35407,
- "git_blob": "a7a8836031c0b7586567c8fe96549642c4535a5e",
+ "bytes": 35482,
+ "git_blob": "75d2647bbc8403934af2bb0c26bcbe2e795b8562",
"mode": "100644",
- "sha256": "e5d2972e13fb73b38d4dd9690e66af0cc36a6545e79523102c1d4040703c7de4"
+ "sha256": "bec40620792cf8f79e7fc7aa6f8027236b559500262ba5cc285008f89af9096e"
},
"core/crates/tera_ffi/tests/logging_error.rs": {
"bytes": 357,
@@ -1124,6 +1136,12 @@
"mode": "100644",
"sha256": "a09d6144bec7938c48781a7648ce40ebac62a47fd5a093477727c1bdf746ed16"
},
+ "core/fixtures/calendar_wire.v1.json": {
+ "bytes": 1962,
+ "git_blob": "69b0644dc24cf31bfd2a45d77f8211184a7da4c2",
+ "mode": "100644",
+ "sha256": "7377d9ebcbb29633e3edc14b1a09b2c92ca8f1f8c21e5ecdb0299d6719bcf1ab"
+ },
"core/provenance/tera_bindgen/LICENSE-APACHE": {
"bytes": 10831,
"git_blob": "9f90a7c2df28eba05d53e5c6f9ac246c018c6bee",
@@ -1533,13 +1551,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 120272,
- "git_blob": "c79579634b4af362ddb7e84ac0a89644f2a980cf",
+ "bytes": 120816,
+ "git_blob": "6cd6bc7b0beb7172b994ee33f8b9f5a499c3fc9b",
"mode": "100644",
- "sha256": "28e4400177809875fee084c8e3546c7ba28c9d7b268fb60186a3bc005e5c296a"
+ "sha256": "f344ae262369369516e9a9923addb2a9cacdf6e5f017024f459e5fa93a78c47d"
}
},
"policy": "staged_inputs",
- "tree": "d66c73094f8b59dc2e016029720be10ebc5ada91"
+ "tree": "2cd97ed5ace482fe1d1836445bc74cd39f4107bc"
}
}
diff --git a/TeraFFI/source/aarch64-apple-ios-sim.json b/TeraFFI/source/aarch64-apple-ios-sim.json
@@ -664,6 +664,12 @@
"mode": "100644",
"sha256": "79fd90c240c67137232e6278e69f87a2159b6e078eb99123823a4fc11ce8fcc8"
},
+ "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs": {
+ "bytes": 9425,
+ "git_blob": "da908dfacbeb6fff82bc618ba4d5e7ec9aa9e6a9",
+ "mode": "100644",
+ "sha256": "3ec65d1cb2d94740396137d03920b212afb74692dba11729e4ce5bb3c5a2a789"
+ },
"core/crates/tera_core/src/runtime/product_surface/context.rs": {
"bytes": 14211,
"git_blob": "92498807101c638cec675e0b49fde1f4ceed17a2",
@@ -743,10 +749,10 @@
"sha256": "76e3bddfc237dac63293d264d68991b489585136fe377e39dbba72aa3a1181f4"
},
"core/crates/tera_core/src/runtime/product_surface/today.rs": {
- "bytes": 140839,
- "git_blob": "2ac582261824b8127a5b12e1effccbc56e3e4e42",
+ "bytes": 140913,
+ "git_blob": "cdbd64d61b33c2e35b4adcbe41834125286caa78",
"mode": "100644",
- "sha256": "ed24b32ba9c956af9723c251eb25fa7a726ea19844392c770b5363352c9fdb62"
+ "sha256": "4ef107bd6e4dd7870fd262dea9efebcc19ed7e6b262a9baa34ebdf8894d2720c"
},
"core/crates/tera_core/src/runtime/product_surface/today_admission_tests.rs": {
"bytes": 14718,
@@ -1042,11 +1048,17 @@
"mode": "100644",
"sha256": "4cb6aa1ff8b006d8a8710e807c9965d47fdd3e72eca67b28a5d909696574f161"
},
+ "core/crates/tera_ffi/tests/local_mvp/calendar_wire_runtime.rs": {
+ "bytes": 6876,
+ "git_blob": "2ba8bf12c3449ac8b73604c5199badf041feac6b",
+ "mode": "100644",
+ "sha256": "7b86747a88a0406f5aac3a8dd753bdafb5e955ac51caf614bd1dee2e90beb50b"
+ },
"core/crates/tera_ffi/tests/local_mvp_real_io.rs": {
- "bytes": 35407,
- "git_blob": "a7a8836031c0b7586567c8fe96549642c4535a5e",
+ "bytes": 35482,
+ "git_blob": "75d2647bbc8403934af2bb0c26bcbe2e795b8562",
"mode": "100644",
- "sha256": "e5d2972e13fb73b38d4dd9690e66af0cc36a6545e79523102c1d4040703c7de4"
+ "sha256": "bec40620792cf8f79e7fc7aa6f8027236b559500262ba5cc285008f89af9096e"
},
"core/crates/tera_ffi/tests/logging_error.rs": {
"bytes": 357,
@@ -1120,6 +1132,12 @@
"mode": "100644",
"sha256": "a09d6144bec7938c48781a7648ce40ebac62a47fd5a093477727c1bdf746ed16"
},
+ "core/fixtures/calendar_wire.v1.json": {
+ "bytes": 1962,
+ "git_blob": "69b0644dc24cf31bfd2a45d77f8211184a7da4c2",
+ "mode": "100644",
+ "sha256": "7377d9ebcbb29633e3edc14b1a09b2c92ca8f1f8c21e5ecdb0299d6719bcf1ab"
+ },
"core/provenance/tera_bindgen/LICENSE-APACHE": {
"bytes": 10831,
"git_blob": "9f90a7c2df28eba05d53e5c6f9ac246c018c6bee",
@@ -1529,13 +1547,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 120272,
- "git_blob": "c79579634b4af362ddb7e84ac0a89644f2a980cf",
+ "bytes": 120816,
+ "git_blob": "6cd6bc7b0beb7172b994ee33f8b9f5a499c3fc9b",
"mode": "100644",
- "sha256": "28e4400177809875fee084c8e3546c7ba28c9d7b268fb60186a3bc005e5c296a"
+ "sha256": "f344ae262369369516e9a9923addb2a9cacdf6e5f017024f459e5fa93a78c47d"
}
},
"policy": "staged_inputs",
- "tree": "d66c73094f8b59dc2e016029720be10ebc5ada91"
+ "tree": "2cd97ed5ace482fe1d1836445bc74cd39f4107bc"
}
}
diff --git a/TeraFFI/source/aarch64-apple-ios.json b/TeraFFI/source/aarch64-apple-ios.json
@@ -664,6 +664,12 @@
"mode": "100644",
"sha256": "79fd90c240c67137232e6278e69f87a2159b6e078eb99123823a4fc11ce8fcc8"
},
+ "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs": {
+ "bytes": 9425,
+ "git_blob": "da908dfacbeb6fff82bc618ba4d5e7ec9aa9e6a9",
+ "mode": "100644",
+ "sha256": "3ec65d1cb2d94740396137d03920b212afb74692dba11729e4ce5bb3c5a2a789"
+ },
"core/crates/tera_core/src/runtime/product_surface/context.rs": {
"bytes": 14211,
"git_blob": "92498807101c638cec675e0b49fde1f4ceed17a2",
@@ -743,10 +749,10 @@
"sha256": "76e3bddfc237dac63293d264d68991b489585136fe377e39dbba72aa3a1181f4"
},
"core/crates/tera_core/src/runtime/product_surface/today.rs": {
- "bytes": 140839,
- "git_blob": "2ac582261824b8127a5b12e1effccbc56e3e4e42",
+ "bytes": 140913,
+ "git_blob": "cdbd64d61b33c2e35b4adcbe41834125286caa78",
"mode": "100644",
- "sha256": "ed24b32ba9c956af9723c251eb25fa7a726ea19844392c770b5363352c9fdb62"
+ "sha256": "4ef107bd6e4dd7870fd262dea9efebcc19ed7e6b262a9baa34ebdf8894d2720c"
},
"core/crates/tera_core/src/runtime/product_surface/today_admission_tests.rs": {
"bytes": 14718,
@@ -1042,11 +1048,17 @@
"mode": "100644",
"sha256": "4cb6aa1ff8b006d8a8710e807c9965d47fdd3e72eca67b28a5d909696574f161"
},
+ "core/crates/tera_ffi/tests/local_mvp/calendar_wire_runtime.rs": {
+ "bytes": 6876,
+ "git_blob": "2ba8bf12c3449ac8b73604c5199badf041feac6b",
+ "mode": "100644",
+ "sha256": "7b86747a88a0406f5aac3a8dd753bdafb5e955ac51caf614bd1dee2e90beb50b"
+ },
"core/crates/tera_ffi/tests/local_mvp_real_io.rs": {
- "bytes": 35407,
- "git_blob": "a7a8836031c0b7586567c8fe96549642c4535a5e",
+ "bytes": 35482,
+ "git_blob": "75d2647bbc8403934af2bb0c26bcbe2e795b8562",
"mode": "100644",
- "sha256": "e5d2972e13fb73b38d4dd9690e66af0cc36a6545e79523102c1d4040703c7de4"
+ "sha256": "bec40620792cf8f79e7fc7aa6f8027236b559500262ba5cc285008f89af9096e"
},
"core/crates/tera_ffi/tests/logging_error.rs": {
"bytes": 357,
@@ -1120,6 +1132,12 @@
"mode": "100644",
"sha256": "a09d6144bec7938c48781a7648ce40ebac62a47fd5a093477727c1bdf746ed16"
},
+ "core/fixtures/calendar_wire.v1.json": {
+ "bytes": 1962,
+ "git_blob": "69b0644dc24cf31bfd2a45d77f8211184a7da4c2",
+ "mode": "100644",
+ "sha256": "7377d9ebcbb29633e3edc14b1a09b2c92ca8f1f8c21e5ecdb0299d6719bcf1ab"
+ },
"core/provenance/tera_bindgen/LICENSE-APACHE": {
"bytes": 10831,
"git_blob": "9f90a7c2df28eba05d53e5c6f9ac246c018c6bee",
@@ -1529,13 +1547,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 120272,
- "git_blob": "c79579634b4af362ddb7e84ac0a89644f2a980cf",
+ "bytes": 120816,
+ "git_blob": "6cd6bc7b0beb7172b994ee33f8b9f5a499c3fc9b",
"mode": "100644",
- "sha256": "28e4400177809875fee084c8e3546c7ba28c9d7b268fb60186a3bc005e5c296a"
+ "sha256": "f344ae262369369516e9a9923addb2a9cacdf6e5f017024f459e5fa93a78c47d"
}
},
"policy": "staged_inputs",
- "tree": "d66c73094f8b59dc2e016029720be10ebc5ada91"
+ "tree": "2cd97ed5ace482fe1d1836445bc74cd39f4107bc"
}
}
diff --git a/core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs b/core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs
@@ -0,0 +1,255 @@
+//! Consumer conformance against the exact shared owner selected by Cargo.lock.
+use radroots_event::calendar::{
+ AuthoredCalendarDateEvent, AuthoredCalendarTimeEvent, CalendarDate,
+};
+use radroots_event_codec::{
+ admission::admit_verified_event,
+ decode::calendar::{
+ admit_radroots_calendar_date_event, admit_radroots_calendar_time_event,
+ parse_nip52_calendar_date_event, parse_nip52_calendar_time_event,
+ },
+ encode::calendar::time_to_wire_parts,
+ verify::verify_nip01_event,
+};
+use serde_json::Value;
+
+use super::tests::{keys, signed_owned};
+use crate::runtime::product_surface::{CreateEvent, Phase1AddCommand};
+
+fn fixtures() -> Value {
+ serde_json::from_str(include_str!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../../fixtures/calendar_wire.v1.json"
+ )))
+ .expect("standalone calendar fixtures")
+}
+
+fn tags(fixture: &Value) -> Vec<Vec<String>> {
+ serde_json::from_value(fixture["tags"].clone()).unwrap()
+}
+
+fn field<'a>(fixture: &'a Value, name: &str) -> &'a str {
+ fixture["tags"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .find(|tag| tag[0] == name)
+ .unwrap()[1]
+ .as_str()
+ .unwrap()
+}
+
+#[test]
+fn authored_calendar_plans_match_current_wire_and_signature_admission() {
+ let suite = fixtures();
+ assert_eq!(suite["schema_version"], 1);
+ assert_eq!(
+ suite["provenance"]["registry_version"],
+ radroots_event::contract::RegistryVersion::CURRENT.get()
+ );
+ assert_eq!(suite["events"].as_array().unwrap().len(), 3);
+ for fixture in suite["events"].as_array().unwrap() {
+ let content = fixture["content"].as_str().unwrap();
+ let event = if fixture["kind"] == 31_922 {
+ CreateEvent::date(
+ AuthoredCalendarDateEvent::new(
+ field(fixture, "d"),
+ field(fixture, "title"),
+ CalendarDate::parse(field(fixture, "start")).unwrap(),
+ )
+ .unwrap()
+ .with_end(CalendarDate::parse(field(fixture, "end")).unwrap())
+ .unwrap()
+ .with_description(content)
+ .unwrap()
+ .with_locations(vec![field(fixture, "location").to_owned()])
+ .unwrap(),
+ )
+ } else {
+ let mut event = AuthoredCalendarTimeEvent::new(
+ field(fixture, "d"),
+ field(fixture, "title"),
+ field(fixture, "start").parse().unwrap(),
+ )
+ .unwrap()
+ .with_end(field(fixture, "end").parse().unwrap())
+ .unwrap()
+ .with_start_tzid(field(fixture, "start_tzid"))
+ .unwrap()
+ .with_description(content)
+ .unwrap()
+ .with_locations(vec![field(fixture, "location").to_owned()])
+ .unwrap();
+ if let Some(zone) = fixture["timing"]["time"]["end_tzid"].as_str() {
+ event = event.with_end_tzid(zone).unwrap();
+ }
+ CreateEvent::time(event)
+ };
+ let plan = Phase1AddCommand::CreateEvent(event)
+ .authored_plan(1_786_000_000, keys().public_key().to_string())
+ .unwrap();
+ assert_eq!(
+ u64::from(plan.body().kind()),
+ fixture["kind"].as_u64().unwrap()
+ );
+ assert_eq!(plan.body().tags(), tags(fixture));
+ assert_eq!(plan.body().content(), content);
+ let signed = signed_owned(
+ plan.body().kind(),
+ plan.body().tags().to_vec(),
+ content,
+ 1_786_000_000,
+ );
+ let admitted =
+ admit_verified_event(verify_nip01_event(signed.envelope().clone()).unwrap()).unwrap();
+ assert_eq!(
+ admitted.contract_id(),
+ fixture["contract_id"].as_str().unwrap()
+ );
+ assert_eq!(admitted.event().tags_as_vec(), tags(fixture));
+ assert_eq!(
+ admitted.event(),
+ signed.envelope(),
+ "admission preserves signed source"
+ );
+ }
+}
+
+fn reject(kind: u32, tags: Vec<Vec<String>>) {
+ let signed = signed_owned(kind, tags, "calendar conformance", 1_786_000_000);
+ let verified =
+ verify_nip01_event(signed.envelope().clone()).expect("valid signed malformed profile");
+ assert!(
+ admit_verified_event(verified).is_err(),
+ "malformed calendar profile admitted"
+ );
+}
+
+fn replace(tags: &mut [Vec<String>], name: &str, value: &str) {
+ tags.iter_mut().find(|tag| tag[0] == name).unwrap()[1] = value.to_owned();
+}
+
+#[test]
+fn signed_calendar_admission_rejects_noncanonical_cardinality_and_fields() {
+ for fixture in fixtures()["events"].as_array().unwrap() {
+ let kind = fixture["kind"].as_u64().unwrap() as u32;
+ for name in ["d", "title", "start"] {
+ let mut missing = tags(fixture);
+ missing.retain(|tag| tag[0] != name);
+ reject(kind, missing);
+ }
+ // Each scalar in these fixtures is singular, exactly two elements.
+ for scalar in tags(fixture).iter().filter(|tag| tag[0] != "D") {
+ let mut duplicate = tags(fixture);
+ duplicate.push(scalar.clone());
+ // location is intentionally repeatable in the shared contract.
+ if scalar[0] != "location" {
+ reject(kind, duplicate);
+ }
+ let mut arity = tags(fixture);
+ arity
+ .iter_mut()
+ .find(|tag| tag[0] == scalar[0])
+ .unwrap()
+ .push("extra".into());
+ reject(kind, arity);
+ }
+ let mut equal_end = tags(fixture);
+ replace(&mut equal_end, "end", field(fixture, "start"));
+ reject(kind, equal_end);
+ if kind == 31_922 {
+ let mut forbidden = tags(fixture);
+ forbidden.push(vec!["D".into(), "20833".into()]);
+ reject(kind, forbidden);
+ let mut invalid = tags(fixture);
+ replace(&mut invalid, "start", "2026-02-29");
+ reject(kind, invalid);
+ } else {
+ for value in ["01800000000", "-1", "18446744073709551616"] {
+ let mut invalid = tags(fixture);
+ replace(&mut invalid, "start", value);
+ reject(kind, invalid);
+ }
+ for value in ["america/vancouver", "Mars/Olympus", "UTC+03"] {
+ let mut invalid = tags(fixture);
+ replace(&mut invalid, "start_tzid", value);
+ reject(kind, invalid);
+ }
+ let mut missing = tags(fixture);
+ missing.retain(|tag| tag[0] != "D");
+ reject(kind, missing);
+ let mut duplicate = tags(fixture);
+ duplicate.push(vec!["D".into(), "20833".into()]);
+ reject(kind, duplicate);
+ }
+ }
+}
+
+#[test]
+fn baseline_observation_does_not_weaken_strict_calendar_day_coverage() {
+ let suite = fixtures();
+ let fixture = &suite["events"][1];
+ for values in [
+ vec!["20833"],
+ vec!["20834", "20833"],
+ vec!["20833", "20833", "20834"],
+ vec!["020833", "20834"],
+ ] {
+ let mut partial = tags(fixture);
+ partial.retain(|tag| tag[0] != "D");
+ partial.extend(values.into_iter().map(|day| vec!["D".into(), day.into()]));
+ let parsed = parse_nip52_calendar_time_event(31_923, &partial, "")
+ .expect("bounded in-range observed days");
+ assert!(admit_radroots_calendar_time_event(parsed).is_err());
+ reject(31_923, partial);
+ }
+ let mut absent = tags(fixture);
+ absent.retain(|tag| tag[0] != "D");
+ assert!(parse_nip52_calendar_time_event(31_923, &absent, "").is_err());
+ let mut date = tags(&suite["events"][0]);
+ date.push(vec!["D".into(), "20833".into()]);
+ let parsed = parse_nip52_calendar_date_event(31_922, &date, "").unwrap();
+ assert!(admit_radroots_calendar_date_event(parsed).is_err());
+}
+
+#[test]
+fn timed_encoder_keeps_exclusive_midnight_and_full_width_bounded_days() {
+ for (start, end, expected) in [
+ (1_800_000_000, None, vec!["20833".to_owned()]),
+ (1_800_000_000, Some(1_800_057_600), vec!["20833".to_owned()]),
+ (
+ 1_800_000_000,
+ Some(1_800_057_601),
+ vec!["20833".to_owned(), "20834".to_owned()],
+ ),
+ (u64::MAX, None, vec![(u64::MAX / 86_400).to_string()]),
+ (
+ 0,
+ Some(366 * 86_400),
+ (0..366).map(|day| day.to_string()).collect(),
+ ),
+ ] {
+ let mut event = AuthoredCalendarTimeEvent::new("boundary", "Boundary", start).unwrap();
+ if let Some(end) = end {
+ event = event.with_end(end).unwrap();
+ }
+ let wire = time_to_wire_parts(&event).unwrap();
+ assert_eq!(wire.kind, 31_923);
+ assert_eq!(
+ wire.tags
+ .iter()
+ .filter(|tag| tag[0] == "D")
+ .map(|tag| tag[1].clone())
+ .collect::<Vec<_>>(),
+ expected
+ );
+ let signed = signed_owned(wire.kind, wire.tags, &wire.content, 1_786_000_000);
+ admit_verified_event(verify_nip01_event(signed.envelope().clone()).unwrap()).unwrap();
+ }
+ assert!(
+ AuthoredCalendarTimeEvent::new("boundary", "Boundary", 0)
+ .unwrap()
+ .with_end(367 * 86_400)
+ .is_err()
+ );
+}
diff --git a/core/crates/tera_core/src/runtime/product_surface/today.rs b/core/crates/tera_core/src/runtime/product_surface/today.rs
@@ -62,6 +62,10 @@ const PROJECTION_CONTENT_DOMAIN: &[u8] = b"radroots.today-content-generation.v2\
const PROJECTION_DOCUMENT_KEY_DOMAIN: &[u8] = b"radroots.today-document-key.v1\0";
const SNAPSHOT_ID_DOMAIN: &[u8] = b"tera.today-snapshot-id.v3\0";
+#[cfg(test)]
+#[path = "calendar_wire_tests.rs"]
+mod calendar_wire_tests;
+
#[path = "today_calendar_migration.rs"]
mod calendar_migration;
diff --git a/core/crates/tera_ffi/tests/local_mvp/calendar_wire_runtime.rs b/core/crates/tera_ffi/tests/local_mvp/calendar_wire_runtime.rs
@@ -0,0 +1,190 @@
+//! Real FFI authoring and fresh SQLite admission of the pinned calendar wire.
+use super::*;
+use nostr::Filter;
+use serde_json::Value;
+use tera_ffi::{FfiCalendarTiming, FfiCivilDate};
+
+fn fixtures() -> Value {
+ serde_json::from_str(include_str!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../../fixtures/calendar_wire.v1.json"
+ )))
+ .unwrap()
+}
+
+fn field<'a>(fixture: &'a Value, name: &str) -> &'a str {
+ fixture["tags"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .find(|tag| tag[0] == name)
+ .unwrap()[1]
+ .as_str()
+ .unwrap()
+}
+
+fn input(fixture: &Value) -> FfiAddDraftInput {
+ let mut input = add_input(
+ FfiAddCommandType::CreateEvent,
+ fixture["content"].as_str().unwrap(),
+ None,
+ );
+ input.identifier = Some(field(fixture, "d").into());
+ input.title = Some(field(fixture, "title").into());
+ input.location = Some(field(fixture, "location").into());
+ if fixture["kind"] == 31_922 {
+ input.event_timing = Some(FfiEventTimingKind::AllDay);
+ input.event_start_date = Some(field(fixture, "start").into());
+ input.event_end_date = Some(field(fixture, "end").into());
+ // An inactive editor zone must never become a civil wire timestamp/tag.
+ input.event_timezone = Some("Pacific/Auckland".into());
+ } else {
+ input.event_timing = Some(FfiEventTimingKind::Timed);
+ input.event_start_unix_s = Some(field(fixture, "start").parse().unwrap());
+ input.event_end_unix_s = Some(field(fixture, "end").parse().unwrap());
+ input.event_timezone = Some(field(fixture, "start_tzid").into());
+ }
+ input
+}
+
+fn expected_timing(fixture: &Value) -> FfiCalendarTiming {
+ if fixture["kind"] == 31_922 {
+ FfiCalendarTiming::DateBased {
+ start: FfiCivilDate {
+ year: 2026,
+ month: 9,
+ day: 5,
+ },
+ end_exclusive: Some(FfiCivilDate {
+ year: 2026,
+ month: 9,
+ day: 7,
+ }),
+ }
+ } else {
+ let timing = &fixture["timing"]["time"];
+ FfiCalendarTiming::TimeBased {
+ start_unix_s: timing["start"].as_u64().unwrap(),
+ end_exclusive_unix_s: timing["end_exclusive"].as_u64(),
+ start_tzid: timing["start_tzid"].as_str().map(str::to_owned),
+ end_tzid: timing["end_tzid"].as_str().map(str::to_owned),
+ }
+ }
+}
+
+#[tokio::test]
+async fn calendar_wire_survives_ffi_publication_fresh_admission_and_reopen() {
+ let suite = fixtures();
+ let fixtures = suite["events"].as_array().unwrap();
+ assert_eq!(fixtures.len(), 3);
+ let relay = MockRelay::run().await.unwrap();
+ let relay_url = relay.url().await.to_string();
+ let context = local_network(&relay_url);
+ let publisher_root = tempfile::tempdir().unwrap();
+ support::prepare(publisher_root.path());
+ let publisher = runtime_with_signer(publisher_root.path()).await;
+ configure_simulator(
+ &publisher,
+ &relay_url,
+ &format!("http://127.0.0.1:{}", unused_loopback_port().await),
+ );
+ for (index, fixture) in fixtures[..2].iter().enumerate() {
+ let id = draft_id(81 + index as u8);
+ let saved = publisher
+ .phase1_save_draft(
+ id.clone(),
+ input(fixture),
+ AUTHORED_AT,
+ None,
+ 1_800_000_000_000 + index as u64,
+ )
+ .await
+ .unwrap();
+ let queued = queue(
+ &publisher,
+ &id,
+ saved.revision,
+ &relay_url,
+ false,
+ 1_800_000_000_100 + index as u64,
+ )
+ .await;
+ advance_complete(&publisher, &id, queued.revision).await;
+ }
+ // The creator has one optional start zone. The independent receive path
+ // must also preserve the shared contract's separate optional end zone.
+ let client = Client::new(Keys::parse(FIXTURE_SECRET).unwrap());
+ client.add_relay(&relay_url).await.unwrap();
+ client.connect().await;
+ client.wait_for_connection(Duration::from_secs(2)).await;
+ let external = &fixtures[2];
+ let wire_tags: Vec<Vec<String>> = serde_json::from_value(external["tags"].clone()).unwrap();
+ client
+ .send_event_builder(
+ EventBuilder::new(Kind::from(31_923), external["content"].as_str().unwrap())
+ .tags(wire_tags.into_iter().map(|tag| Tag::parse(tag).unwrap()))
+ .custom_created_at(Timestamp::from_secs(AUTHORED_AT)),
+ )
+ .await
+ .unwrap();
+ let events = client
+ .fetch_events(
+ Filter::new().kinds([Kind::from(31_922), Kind::from(31_923)]),
+ Duration::from_secs(5),
+ )
+ .await
+ .unwrap();
+ assert_eq!(events.len(), 3);
+ for fixture in fixtures {
+ let event = events
+ .iter()
+ .find(|event| event.content == fixture["content"].as_str().unwrap())
+ .unwrap();
+ event.verify().expect("published wire signature and id");
+ assert_eq!(
+ u64::from(event.kind.as_u16()),
+ fixture["kind"].as_u64().unwrap()
+ );
+ assert_eq!(serde_json::to_value(&event.tags).unwrap(), fixture["tags"]);
+ }
+ let reader_root = tempfile::tempdir().unwrap();
+ support::prepare(reader_root.path());
+ let reader = runtime_with_signer(reader_root.path()).await;
+ reader
+ .configure_simulator_relays(vec![relay_url.clone()])
+ .unwrap();
+ let sync = reader
+ .phase1_sync_today(context.clone(), AS_OF, FfiTodayProjectionUpdate::Rebuild)
+ .await
+ .unwrap();
+ assert_eq!(sync.relay_state, FfiTodayRelaySyncState::Complete);
+ assert_eq!(sync.events_admitted, 3);
+ let cards = collect_pages(&reader, &context, 1, AS_OF).await;
+ assert_eq!(cards.len(), 3);
+ for fixture in fixtures {
+ let event = events
+ .iter()
+ .find(|event| event.content == fixture["content"].as_str().unwrap())
+ .unwrap();
+ let card = cards
+ .iter()
+ .find(|card| card.source_event_id == event.id.to_hex())
+ .unwrap();
+ assert_eq!(card.card_type, FfiTodayCardType::Event);
+ assert_eq!(card.calendar_timing, Some(expected_timing(fixture)));
+ }
+ reader.shutdown().await.unwrap();
+ client.shutdown().await;
+ publisher.shutdown().await.unwrap();
+ relay.shutdown();
+ let reopened = runtime_with_signer(reader_root.path()).await;
+ reopened
+ .configure_simulator_relays(vec![relay_url])
+ .unwrap();
+ let cached = collect_pages(&reopened, &context, 1, AS_OF).await;
+ assert_eq!(
+ cached, cards,
+ "offline reopen preserves exact source and typed timing"
+ );
+ reopened.shutdown().await.unwrap();
+}
diff --git a/core/crates/tera_ffi/tests/local_mvp_real_io.rs b/core/crates/tera_ffi/tests/local_mvp_real_io.rs
@@ -23,6 +23,9 @@ use tokio::net::TcpListener;
#[allow(dead_code)]
mod support;
+#[path = "local_mvp/calendar_wire_runtime.rs"]
+mod calendar_wire_runtime;
+
const AUTHORED_AT: u64 = 1_786_000_000;
const AS_OF: u64 = 1_786_200_000;
const FIXTURE_SECRET: &str = "0000000000000000000000000000000000000000000000000000000000000001";
diff --git a/core/fixtures/calendar_wire.v1.json b/core/fixtures/calendar_wire.v1.json
@@ -0,0 +1,37 @@
+{
+ "schema_version": 1,
+ "provenance": {
+ "repository": "radrootslabs/lib",
+ "reviewed_revision": "13ac1f2135199702a07ba6aa14ab22101f17fcb0",
+ "registry_version": 7,
+ "encoder": "crates/event_codec/src/calendar/encode.rs",
+ "admission": "crates/event/src/contract/registry_v7.rs",
+ "scope": "Current pinned Radroots calendar profiles; reviewed revision is provenance, not an instruction to upgrade dependencies."
+ },
+ "events": [
+ {
+ "id": "date_range",
+ "contract_id": "radroots.calendar.date_event.v1",
+ "kind": 31922,
+ "content": "A two-day local harvest gathering.",
+ "tags": [["d", "harvest-days"], ["title", "Harvest days"], ["start", "2026-09-05"], ["end", "2026-09-07"], ["location", "Fixture field"]],
+ "timing": {"date": {"start": "2026-09-05", "end_exclusive": "2026-09-07"}}
+ },
+ {
+ "id": "time_range",
+ "contract_id": "radroots.calendar.time_event.v1",
+ "kind": 31923,
+ "content": "A timed harvest gathering crossing UTC midnight.",
+ "tags": [["d", "harvest-time"], ["title", "Harvest time"], ["start", "1800000000"], ["end", "1800086400"], ["D", "20833"], ["D", "20834"], ["start_tzid", "America/Vancouver"], ["location", "Fixture field"]],
+ "timing": {"time": {"start": 1800000000, "end_exclusive": 1800086400, "start_tzid": "America/Vancouver", "end_tzid": null}}
+ },
+ {
+ "id": "time_both_zones",
+ "contract_id": "radroots.calendar.time_event.v1",
+ "kind": 31923,
+ "content": "An inbound timed event with independent source zones.",
+ "tags": [["d", "harvest-source-zones"], ["title", "Source zones"], ["start", "1800000000"], ["end", "1800057600"], ["D", "20833"], ["start_tzid", "America/Vancouver"], ["end_tzid", "Pacific/Auckland"], ["location", "Fixture field"]],
+ "timing": {"time": {"start": 1800000000, "end_exclusive": 1800057600, "start_tzid": "America/Vancouver", "end_tzid": "Pacific/Auckland"}}
+ }
+ ]
+}
diff --git a/release/provenance.json b/release/provenance.json
@@ -2,7 +2,7 @@
"artifacts": {
"app_api_sha256": "020924097c0d7efc33128cb8fd3d3b2026d95f57c44da71880e585aff80f070b",
"ffi_api_sha256": "e2e025ee9a29182970f52f53593796afd154cdfb09aba197474577103dcb4ad6",
- "ffi_provenance_sha256": "33eda17ee164b8ec3d38df3586d4336249ad1ed13a65a88467e75888bb7347be",
+ "ffi_provenance_sha256": "1cc7fd2b6773c7d407e06d715d12bb7923b2e8055e473fdecf251f77c06d332c",
"info_plist_sha256": "15ef08b1cdd1096cfb9eeaf5be5bf8f814807a7ca9350bbbb47860fa72ec13ef",
"privacy_manifest_sha256": "a331d51864743ebe4e00dd22360b4a538b6b3ac26a6b3eb54094e60a36959a12",
"sbom_sha256": "236eea371d7a6f95e2c632fe1832abe0cd8f08c4c9b43fcf840accc3e5b674d0",
@@ -22,7 +22,7 @@
"lib_revision": "13ac1f2135199702a07ba6aa14ab22101f17fcb0",
"source_date_epoch": 1787871027,
"swift_package_lock_sha256": "94ae067a374726cdaf6b4ca0a5e44663c57fcdc5334060c5ffef5e79cfbf04c0",
- "tera_ffi_source_tree": "d66c73094f8b59dc2e016029720be10ebc5ada91",
+ "tera_ffi_source_tree": "2cd97ed5ace482fe1d1836445bc74cd39f4107bc",
"xcode_package_lock_sha256": "c7f41934ea25f7a287bdc4f3a6ecabbf09a3a0bdd0f5a3e58183f355ca814096"
},
"version": "0.1.0-alpha"
diff --git a/test-fixtures/legacy-identifiers.v1.json b/test-fixtures/legacy-identifiers.v1.json
@@ -1741,6 +1741,10 @@
{
"path": "core/crates/tera_core/src/runtime/product_surface/calendar_timing.rs",
"count": 2
+ },
+ {
+ "path": "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs",
+ "count": 2
}
]
},
@@ -1751,6 +1755,10 @@
{
"path": "core/crates/tera_core/src/runtime/product_surface/calendar_timing.rs",
"count": 2
+ },
+ {
+ "path": "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs",
+ "count": 2
}
]
},
@@ -4045,6 +4053,10 @@
"count": 1
},
{
+ "path": "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs",
+ "count": 2
+ },
+ {
"path": "core/crates/tera_core/src/runtime/product_surface/identity.rs",
"count": 1
},
@@ -4143,6 +4155,10 @@
"count": 1
},
{
+ "path": "core/crates/tera_core/src/runtime/product_surface/calendar_wire_tests.rs",
+ "count": 1
+ },
+ {
"path": "core/crates/tera_core/src/runtime/product_surface/outbox.rs",
"count": 2
},