commit 308a41d2b0964e8748bcbec0fa728f2568cbc79c
parent 8f06cfe1bc6a4a8c9b0748cdb2943d2e879c0fc8
Author: triesap <tyson@radroots.org>
Date: Fri, 7 Aug 2026 08:14:46 +0000
feat(mobile): focus phase one social domain
- Replace broad field operations with exact card and Add taxonomies.
- Add validated local context, stable identities, ranking, and cursors.
- Classify admitted events without content or media-dependent drift.
- Expose focused catalogs and context creation through mobile FFI.
Diffstat:
3 files changed, 93 insertions(+), 608 deletions(-)
diff --git a/core/crates/tera_ffi/src/remote.rs b/core/crates/tera_ffi/src/remote.rs
@@ -28,6 +28,7 @@ pub struct AppInfoPlatform {
pub build_number: Option<String>,
pub build_sha: Option<String>,
}
+
#[uniffi::remote(Record)]
pub struct RuntimeBuildInfo {
pub crate_name: String,
@@ -54,6 +55,7 @@ pub struct RuntimeInfo {
pub sdk: RuntimeBuildInfo,
pub sdk_closed: bool,
}
+
#[uniffi::remote(Record)]
pub struct SdkCapabilityRecord {
pub id: String,
@@ -76,6 +78,7 @@ pub struct SdkShutdownRecord {
pub state: String,
pub already_closed: bool,
}
+
#[uniffi::remote(Record)]
pub struct NostrIdentityRecord {
pub id: String,
@@ -99,6 +102,7 @@ pub struct NostrHostCustodyIdentity {
pub public_key_hex: String,
pub public_key_npub: String,
}
+
#[uniffi::remote(Enum)]
pub enum NostrLight {
Red,
@@ -149,516 +153,37 @@ pub struct NostrPostEventMetadata {
pub published_at: u64,
pub post: NostrPost,
}
-#[uniffi::remote(Enum)]
-pub enum ContextType {
- Regional,
- Network,
- Farm,
- Buyer,
- Route,
- RoutePartner,
- PickupPoint,
- TraceRecords,
- Hub,
- NetworkSteward,
-}
-
-#[uniffi::remote(Enum)]
-pub enum WorkflowActor {
- NetworkMember,
- ProducerAdmin,
- FarmTeamMember,
- HubOperator,
- TraceLead,
- BuyerSourcingLead,
- BuyerReceiver,
- PickupPointCoordinator,
- RouteCoordinator,
- RoutePartner,
- NetworkSteward,
-}
-
-#[uniffi::remote(Enum)]
-pub enum VisibilityClass {
- LocalDraft,
- FarmPrivate,
- WorkspacePrivate,
- NetworkVisible,
- RouteScoped,
- BuyerScoped,
- PublicCommunity,
- PublicProvenance,
- SecretNeverShared,
-}
-
-#[uniffi::remote(Enum)]
-pub enum AuthorityDomain {
- #[serde(rename = "Relay/group access")]
- RelayGroupAccess,
- #[serde(rename = "Farm/workspace operations authority")]
- FarmWorkspaceOperations,
- #[serde(rename = "Buyer workspace authority")]
- BuyerWorkspace,
- #[serde(rename = "Route coordination authority")]
- RouteCoordination,
- #[serde(rename = "Route execution authority")]
- RouteExecution,
- #[serde(rename = "Receipt authority")]
- Receipt,
- #[serde(rename = "Trace/proof authority")]
- TraceProof,
- #[serde(rename = "Public publishing authority")]
- PublicPublishing,
- #[serde(rename = "Network stewardship authority")]
- NetworkStewardship,
-}
-
-#[uniffi::remote(Enum)]
-pub enum AuthorityAction {
- Submit,
- Publish,
- Share,
- Assign,
- Approve,
- Correct,
- Close,
- Retry,
- Search,
- NavigateRelatedObject,
-}
-
-#[uniffi::remote(Enum)]
-pub enum ObjectKind {
- Region,
- Network,
- Farm,
- BuyerWorkspace,
- Route,
- RoutePartner,
- PickupPoint,
- Hub,
- Food,
- Ask,
- Event,
- Place,
- Task,
- Proof,
- Exception,
- Provenance,
- Update,
- AccessMembership,
- BuyerPacket,
- RouteStop,
- Draft,
- OutboxItem,
- MemberInvite,
- Correction,
-}
-
-#[uniffi::remote(Enum)]
-pub enum ObjectPageFamily {
- Network,
- NetworkRoute,
- FarmWorkspace,
- FarmPublicProfile,
- BuyerWorkspace,
- PickupPointPlace,
- Food,
- Event,
- RouteStop,
- Proof,
- BuyerPacket,
- PublicProvenance,
- Exception,
-}
#[uniffi::remote(Enum)]
pub enum TodayCardType {
- Route,
- Food,
- Ask,
- Event,
- Place,
- Task,
- Proof,
- Exception,
- Provenance,
Update,
- AccessMembership,
- SyncOutbox,
-}
-
-#[uniffi::remote(Enum)]
-pub enum AddActionType {
- Photo,
- Note,
+ PhotoUpdate,
Ask,
- Scan,
- Food,
- Harvest,
- BuyerRequest,
- BuyerCommitment,
- RouteNeed,
- RouteStop,
- PickupEvent,
- Place,
- Proof,
- Exception,
- PublicUpdate,
- Provenance,
- MemberInvite,
- Correction,
-}
-
-#[uniffi::remote(Enum)]
-pub enum AddFlowState {
- NotStarted,
- Draft,
- Editing,
- ValidationFailed,
- ReadyToSubmit,
- Submitted,
- Queued,
- Syncing,
- NeedsApproval,
- Approved,
- Published,
- Shared,
- Confirmed,
- Failed,
- Conflict,
- Discarded,
-}
-
-#[uniffi::remote(Enum)]
-pub enum OutboxBehavior {
- LocalOnly,
- QueueWhenOffline,
- RequireOnline,
- PublishWhenAuthorized,
- ShareWhenAuthorized,
-}
-
-#[uniffi::remote(Enum)]
-pub enum PrototypePathKind {
- ProducerFoodToRoute,
- BuyerCommitmentToRoute,
- RouteCoordinatorAssignment,
-}
-
-#[uniffi::remote(Enum)]
-pub enum RouteExecutionFlowKind {
- RoutePartnerAssignedStops,
- BuyerReceiptConfirmation,
- ExceptionRecovery,
-}
-
-#[uniffi::remote(Enum)]
-pub enum RouteExecutionStepKind {
- AssignedRoute,
- PickupConfirmation,
- DropoffConfirmation,
- ReceiptConfirmation,
- ExceptionReport,
- RecoveryAction,
-}
-
-#[uniffi::remote(Enum)]
-pub enum ProofProvenanceArtifactKind {
- ProofCompleteness,
- BuyerPacketDraft,
- BuyerPacketShared,
- PublicProvenancePreview,
-}
-
-#[uniffi::remote(Enum)]
-pub enum ProofProvenanceReviewState {
- MissingProof,
- Complete,
- Draft,
- ReadyToShare,
- Shared,
- RedactionRequired,
- ReadyToPublish,
- Published,
-}
-
-#[uniffi::remote(Enum)]
-pub enum StewardshipAccessItemKind {
- AccessRequestReview,
- RoleApproval,
- RoutePartnerInvite,
- RoutePoolMetadata,
- PublicModeration,
- InviteAcceptance,
- RequestAccess,
- AccessDenied,
- GroupManagementDeferred,
-}
-
-#[uniffi::remote(Enum)]
-pub enum OutboxState {
- NotQueued,
- Draft,
- Queued,
- Syncing,
- AwaitingAuthority,
- Published,
- Shared,
- Failed,
- Conflict,
- Discarded,
+ Event,
+ FoodAvailability,
}
#[uniffi::remote(Enum)]
-pub enum SyncState {
- Unknown,
- Online,
- Offline,
- Syncing,
- Synced,
- Stale,
- Failed,
-}
-
-#[uniffi::remote(Record)]
-pub struct ObjectRef {
- pub object_type: ObjectKind,
- pub object_id: String,
- pub display_label: String,
-}
-
-#[uniffi::remote(Record)]
-pub struct EventRef {
- pub event_id: String,
- pub relay_url: Option<String>,
- pub kind: Option<u32>,
-}
-
-#[uniffi::remote(Record)]
-pub struct ActiveContext {
- pub context_type: ContextType,
- pub context_ref: ObjectRef,
- pub actor: WorkflowActor,
- pub display_label: String,
- pub visibility_scope: VisibilityClass,
-}
-
-#[uniffi::remote(Record)]
-pub struct AuthorityGate {
- pub domain: AuthorityDomain,
- pub action: AuthorityAction,
- pub actor: WorkflowActor,
- pub context: ActiveContext,
- pub is_required: bool,
- pub is_allowed: bool,
- pub reason: Option<String>,
-}
-
-#[uniffi::remote(Record)]
-pub struct ObjectPageSummary {
- pub object_ref: ObjectRef,
- pub family: ObjectPageFamily,
- pub primary_context: ActiveContext,
- pub title: String,
- pub subtitle: Option<String>,
- pub visibility: VisibilityClass,
- pub visibility_label: String,
- pub required_authority: AuthorityGate,
- pub sync_state: SyncState,
-}
-
-#[uniffi::remote(Record)]
-pub struct TodayCardAction {
- pub id: String,
- pub label: String,
- pub action_type: Option<AddActionType>,
- pub target_object: Option<ObjectRef>,
+pub enum AddCommandType {
+ CreateUpdate,
+ CreatePhotoUpdate,
+ CreateAsk,
+ CreateEvent,
+ CreateFoodAvailability,
}
#[uniffi::remote(Record)]
-pub struct TodayCard {
- pub id: String,
+pub struct CardAddParity {
pub card_type: TodayCardType,
- pub source_object_refs: Vec<ObjectRef>,
- pub source_event_refs: Vec<EventRef>,
- pub primary_context: ActiveContext,
- pub actor: WorkflowActor,
- pub visibility: VisibilityClass,
- pub visibility_label: String,
- pub title: String,
- pub status_line: String,
- pub detail_lines: Vec<String>,
- pub pills: Vec<String>,
- pub primary_action: TodayCardAction,
- pub secondary_action: Option<TodayCardAction>,
- pub ranking_reason: String,
- pub ranking_features: Vec<String>,
- pub sync_state: SyncState,
- pub outbox_state: OutboxState,
- pub is_stale: bool,
- pub is_offline: bool,
-}
-
-#[uniffi::remote(Record)]
-pub struct RelatedObjectRequirement {
- pub object_type: ObjectKind,
- pub relationship_label: String,
- pub is_required: bool,
+ pub add_command_type: AddCommandType,
}
#[uniffi::remote(Record)]
-pub struct ValidationRequirement {
+pub struct LocalNetwork {
pub id: String,
pub label: String,
- pub is_blocking: bool,
-}
-
-#[uniffi::remote(Record)]
-pub struct AddAction {
- pub action_type: AddActionType,
- pub display_label: String,
- pub allowed_context_types: Vec<ContextType>,
- pub required_authority: AuthorityGate,
- pub default_visibility: VisibilityClass,
- pub allowed_visibility_options: Vec<VisibilityClass>,
- pub created_or_updated_object_type: ObjectKind,
- pub related_object_requirements: Vec<RelatedObjectRequirement>,
- pub validation_requirements: Vec<ValidationRequirement>,
- pub supports_offline: bool,
- pub supports_draft: bool,
- pub outbox_behavior: OutboxBehavior,
- pub primary_submit_label: String,
- pub completion_state: AddFlowState,
-}
-
-#[uniffi::remote(Record)]
-pub struct OutboxItem {
- pub id: String,
- pub action_type: AddActionType,
- pub context: ActiveContext,
- pub object_refs: Vec<ObjectRef>,
- pub event_refs: Vec<EventRef>,
- pub visibility: VisibilityClass,
- pub authority_gate: AuthorityGate,
- pub flow_state: AddFlowState,
- pub outbox_state: OutboxState,
- pub sync_state: SyncState,
- pub queued_at_unix: Option<u64>,
- pub last_attempt_at_unix: Option<u64>,
- pub retry_count: u32,
- pub last_error: Option<String>,
-}
-
-#[uniffi::remote(Record)]
-pub struct OutboxRetryDecision {
- pub item_id: String,
- pub is_retryable: bool,
- pub authority_gate: AuthorityGate,
- pub reason: Option<String>,
-}
-
-#[uniffi::remote(Record)]
-pub struct SearchResultSummary {
- pub id: String,
- pub object_ref: ObjectRef,
- pub primary_context: ActiveContext,
- pub title: String,
- pub subtitle: Option<String>,
- pub visibility: VisibilityClass,
- pub visibility_label: String,
- pub required_authority: AuthorityGate,
- pub sync_state: SyncState,
-}
-
-#[uniffi::remote(Record)]
-pub struct PrototypePathStep {
- pub id: String,
- pub label: String,
- pub context: ActiveContext,
- pub action_type: Option<AddActionType>,
- pub object_ref: Option<ObjectRef>,
- pub authority_gate: AuthorityGate,
- pub visibility: VisibilityClass,
- pub outbox_state: OutboxState,
- pub sync_state: SyncState,
-}
-
-#[uniffi::remote(Record)]
-pub struct PrototypePath {
- pub id: String,
- pub kind: PrototypePathKind,
- pub title: String,
- pub actor: WorkflowActor,
- pub context: ActiveContext,
- pub steps: Vec<PrototypePathStep>,
-}
-
-#[uniffi::remote(Record)]
-pub struct RouteExecutionStep {
- pub id: String,
- pub kind: RouteExecutionStepKind,
- pub label: String,
- pub actor: WorkflowActor,
- pub context: ActiveContext,
- pub route_ref: ObjectRef,
- pub object_ref: Option<ObjectRef>,
- pub required_authority: AuthorityGate,
- pub visibility: VisibilityClass,
- pub supports_offline: bool,
- pub supports_partial_receipt: bool,
- pub uses_receipt_token: bool,
- pub outbox_state: OutboxState,
- pub sync_state: SyncState,
- pub detail_lines: Vec<String>,
-}
-
-#[uniffi::remote(Record)]
-pub struct RouteExecutionFlow {
- pub id: String,
- pub kind: RouteExecutionFlowKind,
- pub title: String,
- pub actor: WorkflowActor,
- pub context: ActiveContext,
- pub route_ref: ObjectRef,
- pub steps: Vec<RouteExecutionStep>,
-}
-
-#[uniffi::remote(Record)]
-pub struct ProofProvenanceArtifact {
- pub id: String,
- pub kind: ProofProvenanceArtifactKind,
- pub review_state: ProofProvenanceReviewState,
- pub title: String,
- pub actor: WorkflowActor,
- pub context: ActiveContext,
- pub object_ref: ObjectRef,
- pub source_object_refs: Vec<ObjectRef>,
- pub required_authority: AuthorityGate,
- pub visibility: VisibilityClass,
- pub is_public_preview: bool,
- pub requires_redaction_review: bool,
- pub can_publish: bool,
- pub public_summary_lines: Vec<String>,
- pub redacted_field_labels: Vec<String>,
- pub outbox_state: OutboxState,
- pub sync_state: SyncState,
-}
-
-#[uniffi::remote(Record)]
-pub struct StewardshipAccessItem {
- pub id: String,
- pub kind: StewardshipAccessItemKind,
- pub title: String,
- pub actor: WorkflowActor,
- pub context: ActiveContext,
- pub target_ref: ObjectRef,
- pub required_authority: AuthorityGate,
- pub visibility: VisibilityClass,
- pub is_admin_lite: bool,
- pub is_phase_2_deferred: bool,
- pub grants_private_access: bool,
- pub outbox_state: OutboxState,
- pub sync_state: SyncState,
- pub detail_lines: Vec<String>,
+ pub relay_urls: Vec<String>,
+ pub locality: Option<String>,
+ pub followed_authors: Vec<String>,
+ pub generation: u64,
}
diff --git a/core/crates/tera_ffi/src/runtime.rs b/core/crates/tera_ffi/src/runtime.rs
@@ -2,11 +2,7 @@ use radroots_mobile_core::runtime::{
info::RuntimeInfo,
key_management::{NostrHostCustodyIdentity, NostrIdentityRecord, NostrIdentitySnapshot},
nostr::{NostrConnectionStatus, NostrPostEventMetadata, NostrProfileEventMetadata},
- product_surface::{
- ActiveContext, AddAction, AuthorityAction, AuthorityDomain, AuthorityGate,
- ObjectPageSummary, OutboxItem, OutboxRetryDecision, ProofProvenanceArtifact, PrototypePath,
- RouteExecutionFlow, SearchResultSummary, StewardshipAccessItem, TodayCard, WorkflowActor,
- },
+ product_surface::{AddCommandType, CardAddParity, LocalNetwork, TodayCardType},
sdk::{SdkCapabilityRecord, SdkShutdownRecord, SdkStorageStatusRecord},
};
@@ -204,74 +200,36 @@ impl RadrootsRuntime {
.map_err(Into::into)
}
- pub fn phase1_active_contexts(&self) -> Vec<ActiveContext> {
- self.inner.phase1_active_contexts()
+ pub fn phase1_card_types(&self) -> Vec<TodayCardType> {
+ self.inner.phase1_card_types()
}
- pub fn phase1_today_cards(&self, context_id: Option<String>) -> Vec<TodayCard> {
- self.inner.phase1_today_cards(context_id)
+ pub fn phase1_add_command_types(&self) -> Vec<AddCommandType> {
+ self.inner.phase1_add_command_types()
}
- pub fn phase1_add_actions(&self, context_id: Option<String>) -> Vec<AddAction> {
- self.inner.phase1_add_actions(context_id)
+ pub fn phase1_card_add_parity(&self) -> Vec<CardAddParity> {
+ self.inner.phase1_card_add_parity()
}
- pub fn phase1_object_page_summaries(
+ pub fn phase1_local_network(
&self,
- context_id: Option<String>,
- ) -> Vec<ObjectPageSummary> {
- self.inner.phase1_object_page_summaries(context_id)
- }
-
- pub fn phase1_outbox_snapshot(&self) -> Vec<OutboxItem> {
- self.inner.phase1_outbox_snapshot()
- }
-
- pub fn phase1_search_results(
- &self,
- query: Option<String>,
- context_id: Option<String>,
- ) -> Vec<SearchResultSummary> {
- self.inner.phase1_search_results(query, context_id)
- }
-
- pub fn phase1_prototype_paths(&self) -> Vec<PrototypePath> {
- self.inner.phase1_prototype_paths()
- }
-
- pub fn phase1_route_execution_flows(
- &self,
- context_id: Option<String>,
- ) -> Vec<RouteExecutionFlow> {
- self.inner.phase1_route_execution_flows(context_id)
- }
-
- pub fn phase1_proof_provenance_artifacts(
- &self,
- context_id: Option<String>,
- ) -> Vec<ProofProvenanceArtifact> {
- self.inner.phase1_proof_provenance_artifacts(context_id)
- }
-
- pub fn phase1_stewardship_access_items(
- &self,
- context_id: Option<String>,
- ) -> Vec<StewardshipAccessItem> {
- self.inner.phase1_stewardship_access_items(context_id)
- }
-
- pub fn phase1_outbox_retry_decision(&self, item: OutboxItem) -> OutboxRetryDecision {
- self.inner.phase1_outbox_retry_decision(item)
- }
-
- pub fn phase1_check_authority(
- &self,
- actor: WorkflowActor,
- context: ActiveContext,
- domain: AuthorityDomain,
- action: AuthorityAction,
- ) -> AuthorityGate {
- self.inner
- .phase1_check_authority(actor, context, domain, action)
+ id: String,
+ label: String,
+ relay_urls: Vec<String>,
+ locality: Option<String>,
+ followed_authors: Vec<String>,
+ generation: u64,
+ ) -> Result<LocalNetwork, RadrootsAppError> {
+ self.inner
+ .phase1_local_network(
+ id,
+ label,
+ relay_urls,
+ locality,
+ followed_authors,
+ generation,
+ )
+ .map_err(Into::into)
}
}
diff --git a/core/crates/tera_ffi/tests/runtime_delegation.rs b/core/crates/tera_ffi/tests/runtime_delegation.rs
@@ -1,6 +1,4 @@
-use radroots_mobile_core::runtime::product_surface::{
- AuthorityAction, AuthorityDomain, OutboxState,
-};
+use radroots_mobile_core::runtime::product_surface::{AddCommandType, TodayCardType};
use radroots_mobile_ffi::{RadrootsAppError, RadrootsRuntime};
const SECRET: &str = "0000000000000000000000000000000000000000000000000000000000000001";
@@ -120,53 +118,57 @@ async fn native_boundary_delegates_the_complete_core_surface() {
Err(RadrootsAppError::Unsupported(_))
));
- let contexts = runtime.phase1_active_contexts();
- let context = contexts.first().expect("context").clone();
- let context_id = Some(context.context_ref.object_id.clone());
- assert!(!runtime.phase1_today_cards(context_id.clone()).is_empty());
- assert!(!runtime.phase1_add_actions(context_id.clone()).is_empty());
- assert!(
- !runtime
- .phase1_object_page_summaries(context_id.clone())
- .is_empty()
- );
- let outbox = runtime.phase1_outbox_snapshot();
- let failed = outbox
- .into_iter()
- .find(|item| item.outbox_state == OutboxState::Failed)
- .expect("failed outbox item");
- assert!(runtime.phase1_outbox_retry_decision(failed).is_retryable);
- assert!(
- !runtime
- .phase1_search_results(Some("farm".to_owned()), context_id.clone())
- .is_empty()
- );
- assert!(!runtime.phase1_prototype_paths().is_empty());
- assert!(
- !runtime
- .phase1_route_execution_flows(context_id.clone())
- .is_empty()
- );
- assert!(
- !runtime
- .phase1_proof_provenance_artifacts(context_id.clone())
- .is_empty()
- );
- assert!(
- !runtime
- .phase1_stewardship_access_items(context_id)
- .is_empty()
+ assert_eq!(
+ runtime.phase1_card_types(),
+ vec![
+ TodayCardType::Update,
+ TodayCardType::PhotoUpdate,
+ TodayCardType::Ask,
+ TodayCardType::Event,
+ TodayCardType::FoodAvailability,
+ ]
);
assert_eq!(
+ runtime.phase1_add_command_types(),
+ vec![
+ AddCommandType::CreateUpdate,
+ AddCommandType::CreatePhotoUpdate,
+ AddCommandType::CreateAsk,
+ AddCommandType::CreateEvent,
+ AddCommandType::CreateFoodAvailability,
+ ]
+ );
+ let parity = runtime.phase1_card_add_parity();
+ assert_eq!(parity.len(), 5);
+ for (index, item) in parity.iter().enumerate() {
+ assert_eq!(item.card_type, runtime.phase1_card_types()[index]);
+ assert_eq!(
+ item.add_command_type,
+ runtime.phase1_add_command_types()[index]
+ );
+ }
+ let local_network = runtime
+ .phase1_local_network(
+ "nearby".to_owned(),
+ "Near me".to_owned(),
+ vec!["wss://relay.example".to_owned()],
+ Some("u10h".to_owned()),
+ vec!["a".repeat(64)],
+ 1,
+ )
+ .expect("valid local network");
+ assert_eq!(local_network.id, "nearby");
+ assert!(
runtime
- .phase1_check_authority(
- context.actor,
- context.clone(),
- AuthorityDomain::RelayGroupAccess,
- AuthorityAction::Search,
+ .phase1_local_network(
+ "nearby".to_owned(),
+ "Near me".to_owned(),
+ Vec::new(),
+ None,
+ Vec::new(),
+ 1,
)
- .context,
- context
+ .is_err()
);
runtime.shutdown().await.expect("shutdown");