This commit adds the read path (Cortex) to complement the write path (Spine): ## Crates - stemedb-api: HTTP API with axum + utoipa OpenAPI - /v1/assert, /v1/query, /v1/epoch, /v1/skeptic, /v1/trace, /v1/audit - Metered endpoints with quota enforcement - Ed25519 signature verification - stemedb-lens: Truth resolution lenses - RecencyLens, ConsensusLens, ConfidenceLens - VoteAwareConsensusLens (Ballot Box pattern) - TrustAwareAuthorityLens (The Hive pattern) - SkepticLens (conflict analysis) - EpochAwareLens (paradigm-safe queries) - stemedb-query: Query engine with materialized views ## Storage Extensions - VoteStore: Vote aggregation with cached counts - TrustRankStore: Agent reputation with decay - AuditStore: Query audit trail - IndexStore: SP/P/S index structures - SupersessionStore: Epoch supersession chains ## SDKs - sdk/go/steme: Go HTTP client with Ed25519 signing - sdk/go/adk: ADK-Go tools for AI agents ## Documentation - Updated CLAUDE.md, architecture.md, roadmap.md - New ai-lookup entries for all services - Use case docs for consumer health intelligence - Arena roadmap for simulation advancement Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
78 lines
2.4 KiB
Rust
78 lines
2.4 KiB
Rust
//! Storage-layer serialization helpers that map core serde errors to StorageError.
|
|
//!
|
|
//! This module provides a single source of truth for serialization in the storage layer,
|
|
//! eliminating duplication of the error mapping pattern across all store implementations.
|
|
//!
|
|
//! # Usage
|
|
//!
|
|
//! ```ignore
|
|
//! use crate::serde_helpers::{serialize, deserialize};
|
|
//!
|
|
//! fn store_item(&self, item: &MyItem) -> Result<()> {
|
|
//! let bytes = serialize(item)?;
|
|
//! self.kv.put(&key, &bytes)?;
|
|
//! Ok(())
|
|
//! }
|
|
//!
|
|
//! fn load_item(&self, key: &[u8]) -> Result<MyItem> {
|
|
//! let bytes = self.kv.get(key)?.ok_or_else(|| StorageError::NotFound(...))?;
|
|
//! deserialize(&bytes)
|
|
//! }
|
|
//! ```
|
|
|
|
use crate::error::{Result, StorageError};
|
|
|
|
/// Serialize a value using the canonical stemedb_core::serde module.
|
|
///
|
|
/// Maps serialization errors to [`StorageError::Serialization`].
|
|
pub fn serialize<T>(value: &T) -> Result<Vec<u8>>
|
|
where
|
|
T: rkyv::Serialize<rkyv::ser::serializers::AllocSerializer<4096>>,
|
|
{
|
|
stemedb_core::serde::serialize(value).map_err(|e| StorageError::Serialization(e.to_string()))
|
|
}
|
|
|
|
/// Deserialize a value using the canonical stemedb_core::serde module.
|
|
///
|
|
/// Maps deserialization errors to [`StorageError::Serialization`].
|
|
pub fn deserialize<T>(data: &[u8]) -> Result<T>
|
|
where
|
|
T: rkyv::Archive,
|
|
T::Archived: for<'a> rkyv::CheckBytes<rkyv::validation::validators::DefaultValidator<'a>>
|
|
+ rkyv::Deserialize<T, rkyv::Infallible>,
|
|
{
|
|
stemedb_core::serde::deserialize(data).map_err(|e| StorageError::Serialization(e.to_string()))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[derive(Debug, PartialEq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
|
#[archive(check_bytes)]
|
|
struct TestItem {
|
|
id: u64,
|
|
name: String,
|
|
}
|
|
|
|
#[test]
|
|
fn test_roundtrip() {
|
|
let item = TestItem { id: 42, name: "test".to_string() };
|
|
|
|
let bytes = serialize(&item).expect("serialize should succeed");
|
|
let recovered: TestItem = deserialize(&bytes).expect("deserialize should succeed");
|
|
|
|
assert_eq!(item, recovered);
|
|
}
|
|
|
|
#[test]
|
|
fn test_deserialize_invalid_data() {
|
|
let garbage = vec![0xFF, 0xFE, 0xFD];
|
|
let result: Result<TestItem> = deserialize(&garbage);
|
|
|
|
assert!(result.is_err());
|
|
let err = result.unwrap_err();
|
|
assert!(matches!(err, StorageError::Serialization(_)));
|
|
}
|
|
}
|