commit 718cb65037a8b5336eb3063886c4a1cc69a9f14e
parent 2292464ef61c4b953f496da98c0962c286db43e2
Author: triesap <tyson@radroots.org>
Date: Mon, 10 Aug 2026 17:32:12 +0000
feat: persist verified inbound media receipts
Separate signed structural references from retrieval state and exact-byte receipts.
Persist a configuration-scoped, content-addressed, bounded LRU cache and fail closed across eviction, corruption, metadata drift, and legacy migration.
Diffstat:
2 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/core/crates/tera_ffi/src/dto.rs b/core/crates/tera_ffi/src/dto.rs
@@ -22,9 +22,9 @@ use radroots_mobile_core::runtime::{
product_surface::{
AddCommandType, CardLifecycleState, CreateAsk, CreateEvent, CreateFoodAvailability,
CreatePhotoUpdate, CreateUpdate, LocalNetwork, LocalNetworkRelayPolicy, MeSnapshot,
- MediaReference, MediaVerificationState, Phase1AddCommand, Phase1CancellationPolicy,
- Phase1DraftEventTiming, Phase1DraftFormSnapshot, Phase1DraftKind, Phase1DraftMediaSnapshot,
- Phase1DraftStatus, Phase1MediaPrerequisite, Phase1MediaStage, Phase1OutboxState,
+ MediaReference, Phase1AddCommand, Phase1CancellationPolicy, Phase1DraftEventTiming,
+ Phase1DraftFormSnapshot, Phase1DraftKind, Phase1DraftMediaSnapshot, Phase1DraftStatus,
+ Phase1InboundMediaState, Phase1MediaPrerequisite, Phase1MediaStage, Phase1OutboxState,
Phase1QueuePolicy, Phase1RelaySatisfaction, Phase1UploadIntent, ProfileSummary,
SearchResult, SearchResultType, SupportingProfile, ThreadEntry, TodayCard, TodayCardType,
TodayPage, TodayProjectionUpdate, TodayRefreshReceipt, TodayRelaySyncState,
@@ -262,13 +262,13 @@ pub enum FfiMediaVerificationState {
}
#[cfg_attr(coverage_nightly, coverage(off))]
-impl From<MediaVerificationState> for FfiMediaVerificationState {
- fn from(value: MediaVerificationState) -> Self {
+impl From<&Phase1InboundMediaState> for FfiMediaVerificationState {
+ fn from(value: &Phase1InboundMediaState) -> Self {
match value {
- MediaVerificationState::Pending => Self::Pending,
- MediaVerificationState::Verified => Self::Verified,
- MediaVerificationState::Failed => Self::Failed,
- MediaVerificationState::Unavailable => Self::Unavailable,
+ Phase1InboundMediaState::Pending(_) => Self::Pending,
+ Phase1InboundMediaState::Verified(_) => Self::Verified,
+ Phase1InboundMediaState::Failed(_) => Self::Failed,
+ Phase1InboundMediaState::Unavailable => Self::Unavailable,
}
}
}
@@ -289,16 +289,17 @@ pub struct FfiMediaReferenceRecord {
#[cfg_attr(coverage_nightly, coverage(off))]
impl From<MediaReference> for FfiMediaReferenceRecord {
fn from(value: MediaReference) -> Self {
+ let structural = value.structural();
Self {
schema_version: MOBILE_FFI_SCHEMA_VERSION,
- url: value.url,
- sha256: value.sha256,
- media_type: value.media_type,
- width: value.width,
- height: value.height,
- byte_size: value.byte_size,
- alt: value.alt,
- verification: value.verification.into(),
+ url: structural.source_url().to_owned(),
+ sha256: structural.expected_sha256().map(str::to_owned),
+ media_type: structural.expected_media_type().map(str::to_owned),
+ width: structural.expected_width(),
+ height: structural.expected_height(),
+ byte_size: structural.expected_byte_size(),
+ alt: structural.alt().map(str::to_owned),
+ verification: value.retrieval().into(),
}
}
}
diff --git a/core/crates/tera_ffi/src/error.rs b/core/crates/tera_ffi/src/error.rs
@@ -147,6 +147,7 @@ impl From<TodayError> for RadrootsAppError {
("today_cursor_invalid", true, &["restart_pagination"][..])
}
TodayError::RuntimeUnavailable => ("today_runtime_unavailable", true, &["retry"][..]),
+ TodayError::InboundMedia(_) => ("today_media_invalid", false, &["retry_media"][..]),
TodayError::CorruptProjection | TodayError::Serialization | TodayError::Storage(_) => {
("today_state_failed", true, &["rebuild", "retry"][..])
}