From 3dda58a5398abc2a101fc45e09a93dc1cfe43dd2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 18:59:01 +0200 Subject: [PATCH] Collapse Persona feedback ingress into Resident Self --- Cargo.toml | 4 - .../bin/epiphany-persona-feedback-ingress.rs | 181 -------------- epiphany-core/src/lib.rs | 6 +- .../src/persona_feedback_admission.rs | 235 +----------------- epiphany-release-construction/src/lib.rs | 4 - 5 files changed, 4 insertions(+), 426 deletions(-) delete mode 100644 epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs diff --git a/Cargo.toml b/Cargo.toml index 9f48cba9..996a4c84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,10 +109,6 @@ path = "epiphany-core/src/bin/epiphany-host-identity.rs" name = "epiphany-swarm" path = "epiphany-core/src/bin/epiphany-swarm.rs" -[[bin]] -name = "epiphany-persona-feedback-ingress" -path = "epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs" - [[bin]] name = "epiphany-persona-service" path = "epiphany-openai-runtime/src/bin/epiphany-persona-service.rs" diff --git a/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs b/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs deleted file mode 100644 index 574573ef..00000000 --- a/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs +++ /dev/null @@ -1,181 +0,0 @@ -use anyhow::{Result, anyhow}; -use epiphany_core::{ - apply_bifrost_persona_feedback_snapshot, import_bifrost_persona_feedback_deliveries, - validate_bifrost_persona_feedback_source, validate_persona_feedback_store_separation, -}; -use serde::Serialize; -use std::collections::BTreeMap; -use std::env; -use std::path::PathBuf; - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct IngressProjection { - schema_version: &'static str, - status: &'static str, - runtime_id: String, - repository: String, - persona_id: String, - applicable_delivery_count: usize, - present_pressure_count: usize, - authority: &'static str, - private_state_exposed: bool, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct SnapshotProjection { - schema_version: &'static str, - status: &'static str, - runtime_id: String, - repository: String, - persona_id: String, - applied_delivery_count: usize, - authority: &'static str, - private_state_exposed: bool, -} - -fn import_projection_status(present_pressure_count: usize) -> &'static str { - if present_pressure_count == 0 { - "no-applicable-deliveries" - } else { - "pressure-present" - } -} - -fn main() -> Result<()> { - let mut args = env::args().skip(1); - let command = args.next().ok_or_else(|| anyhow!("use status or import"))?; - let mut values = BTreeMap::new(); - while let Some(flag) = args.next() { - let value = args - .next() - .ok_or_else(|| anyhow!("missing value for {flag}"))?; - values.insert(flag, value); - } - let required = |name: &str| -> Result { - values - .get(name) - .cloned() - .ok_or_else(|| anyhow!("missing {name}")) - }; - let source_store = PathBuf::from(required("--source-store")?); - let trust_anchor = PathBuf::from(required("--trust-anchor")?); - let runtime_id = required("--runtime-id")?; - let repository = required("--repository")?; - let persona_id = required("--persona-id")?; - if command == "apply-snapshot" { - let snapshot = PathBuf::from(required("--snapshot")?); - let applied_delivery_count = apply_bifrost_persona_feedback_snapshot( - &snapshot, - &source_store, - &trust_anchor, - &runtime_id, - &repository, - &persona_id, - )?; - println!( - "{}", - serde_json::to_string_pretty(&SnapshotProjection { - schema_version: "epiphany.persona_feedback.snapshot_projection.v0", - status: "applied", - runtime_id, - repository, - persona_id, - applied_delivery_count, - authority: "transport-only", - private_state_exposed: false, - })? - ); - return Ok(()); - } - let (status, applicable_delivery_count, present_pressure_count) = match command.as_str() { - "status" => ( - "ready", - validate_bifrost_persona_feedback_source( - &source_store, - &trust_anchor, - &runtime_id, - &repository, - &persona_id, - )?, - 0, - ), - "import" => { - let feedback_store = PathBuf::from(required("--persona-feedback-store")?); - let resident_store = PathBuf::from(required("--resident-store")?); - let runtime_store = PathBuf::from(required("--runtime-store")?); - let mind_store = PathBuf::from(required("--mind-store")?); - let release_store = PathBuf::from(required("--release-store")?); - validate_persona_feedback_store_separation( - &source_store, - &feedback_store, - &[ - &trust_anchor, - &resident_store, - &runtime_store, - &mind_store, - &release_store, - ], - )?; - let admitted = import_bifrost_persona_feedback_deliveries( - &source_store, - &feedback_store, - &trust_anchor, - &runtime_id, - &repository, - &persona_id, - )?; - ( - import_projection_status(admitted.len()), - admitted.len(), - admitted.len(), - ) - } - _ => { - return Err(anyhow!( - "unknown command {command:?}; use status, apply-snapshot, or import" - )); - } - }; - println!( - "{}", - serde_json::to_string_pretty(&IngressProjection { - schema_version: "epiphany.persona_feedback.ingress_projection.v1", - status, - runtime_id, - repository, - persona_id, - applicable_delivery_count, - present_pressure_count, - authority: "resident-pressure-only", - private_state_exposed: false, - })? - ); - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn import_projection_does_not_call_absence_admission() { - assert_eq!(import_projection_status(0), "no-applicable-deliveries"); - assert_eq!(import_projection_status(1), "pressure-present"); - let encoded = serde_json::to_value(IngressProjection { - schema_version: "epiphany.persona_feedback.ingress_projection.v1", - status: import_projection_status(0), - runtime_id: "epiphany-yggdrasil".into(), - repository: "GameCult/Alien".into(), - persona_id: "epiphany".into(), - applicable_delivery_count: 0, - present_pressure_count: 0, - authority: "resident-pressure-only", - private_state_exposed: false, - }) - .expect("projection serializes"); - assert_eq!(encoded["status"], "no-applicable-deliveries"); - assert!(encoded.get("admittedCount").is_none()); - } -} diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index 4842f20c..d420db2f 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -186,15 +186,15 @@ pub use persona_discord_crossing::*; pub use persona_discord_permit::*; pub use persona_feedback_admission::{ BIFROST_PERSONA_FEEDBACK_ADMISSION_SCHEMA_VERSION, BIFROST_PERSONA_FEEDBACK_DELIVERY_TYPE, - BIFROST_PERSONA_FEEDBACK_RECEIPT_SCHEMA_VERSION, BifrostPersonaFeedbackAdmission, + BifrostPersonaFeedbackAdmission, LOCAL_PERSONA_FEEDBACK_SCHEMA_VERSION, LocalAdmittedPersonaFeedback, PERSONA_FEEDBACK_SOCIAL_ADMISSION_SCHEMA_VERSION, PersonaFeedbackPacket, PersonaFeedbackSocialAdmissionReceipt, admit_bifrost_persona_feedback, admit_persona_feedback_to_social, admitted_persona_feedback, - apply_bifrost_persona_feedback_snapshot, import_bifrost_persona_feedback_deliveries, + import_bifrost_persona_feedback_deliveries, persona_feedback_admission_signing_payload, persona_feedback_admission_signing_purpose, persona_feedback_packet_sha256, persona_feedback_ready_for_cognition, - validate_bifrost_persona_feedback_source, validate_persona_feedback_store_separation, + validate_persona_feedback_store_separation, }; pub use persona_social_state::*; pub use persona_turn::PERSONA_INTERPRETER_EFFECT_DOCUMENT_SCHEMA_VERSION; diff --git a/epiphany-core/src/persona_feedback_admission.rs b/epiphany-core/src/persona_feedback_admission.rs index 9666b2b3..3b905461 100644 --- a/epiphany-core/src/persona_feedback_admission.rs +++ b/epiphany-core/src/persona_feedback_admission.rs @@ -1,12 +1,8 @@ use anyhow::{Result, anyhow, bail}; use cultcache_rs::{ - CacheBackingStore, CultCache, CultCacheEnvelope, DatabaseEntry, PushAllOptions, + CacheBackingStore, CultCache, CultCacheEnvelope, DatabaseEntry, SingleFileMessagePackBackingStore, }; -use cultnet_rs::{ - CultNetMessage, CultNetRawPayloadEncoding, CultNetWireContract, - decode_cultnet_message_from_slice, -}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::path::Path; @@ -19,8 +15,6 @@ use crate::{ pub const BIFROST_PERSONA_FEEDBACK_ADMISSION_SCHEMA_VERSION: &str = "bifrost.persona_feedback.delivery.v0"; pub const BIFROST_PERSONA_FEEDBACK_DELIVERY_TYPE: &str = "bifrost.persona_feedback.delivery"; -pub const BIFROST_PERSONA_FEEDBACK_RECEIPT_SCHEMA_VERSION: &str = - "bifrost.persona_feedback.admission_receipt.v0"; pub const LOCAL_PERSONA_FEEDBACK_SCHEMA_VERSION: &str = "epiphany.persona_feedback.admitted_pressure.v0"; pub const PERSONA_FEEDBACK_SOCIAL_ADMISSION_SCHEMA_VERSION: &str = @@ -539,87 +533,6 @@ pub fn import_bifrost_persona_feedback_deliveries( .collect() } -/// Applies one immutable Bifrost CultNet export to the local crossing source. -/// -/// The snapshot is decoded and every delivery is authenticated before the -/// complete local source store is replaced. Bifrost admission receipts may -/// accompany the export as transport evidence, but are deliberately not -/// persisted into Epiphany's delivery-only source store. -pub fn apply_bifrost_persona_feedback_snapshot( - snapshot_path: &Path, - source_store: &Path, - trust_anchor_path: &Path, - expected_runtime_id: &str, - expected_repository: &str, - expected_persona_id: &str, -) -> Result { - let message = decode_cultnet_message_from_slice( - &std::fs::read(snapshot_path)?, - CultNetWireContract::CultNetSchemaV0, - )?; - let CultNetMessage::SnapshotResponseRaw { documents, .. } = message else { - bail!("Bifrost Persona feedback crossing requires cultnet.snapshot_response_raw.v0"); - }; - let anchor: HostIdentityTrustAnchorEntry = - rmp_serde::from_slice(&std::fs::read(trust_anchor_path)?).map_err(|error| { - anyhow!("Bifrost Persona feedback trust anchor is malformed: {error}") - })?; - - let mut identities = std::collections::BTreeMap::new(); - let mut staged = Vec::new(); - for document in documents { - if document.schema_id == BIFROST_PERSONA_FEEDBACK_RECEIPT_SCHEMA_VERSION { - continue; - } - if document.schema_id != BIFROST_PERSONA_FEEDBACK_ADMISSION_SCHEMA_VERSION { - bail!( - "Bifrost Persona feedback snapshot contains foreign schema {:?}", - document.schema_id - ); - } - if document.payload_encoding != CultNetRawPayloadEncoding::Messagepack { - bail!("Bifrost Persona feedback delivery is not MessagePack"); - } - let delivery: BifrostPersonaFeedbackAdmission = rmp_serde::from_slice(&document.payload) - .map_err(|error| anyhow!("Bifrost Persona feedback delivery is malformed: {error}"))?; - if document.record_key != delivery.admission_id { - bail!("Bifrost Persona feedback record key does not match admission identity"); - } - validate_bifrost_persona_feedback_admission( - &delivery, - &anchor, - expected_runtime_id, - expected_repository, - expected_persona_id, - )?; - let identity = ( - delivery.packet_sha256.clone(), - delivery.admission_id.clone(), - ); - if identities - .insert(delivery.packet.feedback_id.clone(), identity.clone()) - .is_some_and(|existing| existing != identity) - { - bail!("Bifrost Persona feedback snapshot contains a feedback identity collision"); - } - staged.push(CultCacheEnvelope { - key: document.record_key, - r#type: BIFROST_PERSONA_FEEDBACK_DELIVERY_TYPE.into(), - payload: document.payload, - stored_at: document.stored_at, - // CultCache's persisted schema catalog owns the document type for - // this local source. The wire schema version was validated above; - // retaining it here would reclassify the envelope as that version - // string when the store is reopened. - schema_id: Some(BIFROST_PERSONA_FEEDBACK_DELIVERY_TYPE.into()), - }); - } - staged.sort_by(|left, right| left.key.cmp(&right.key)); - let mut backing = SingleFileMessagePackBackingStore::new(source_store); - backing.push_all(&staged, PushAllOptions::default())?; - Ok(staged.len()) -} - pub fn validate_persona_feedback_store_separation( source_store: &Path, feedback_store: &Path, @@ -653,24 +566,6 @@ fn paths_share_storage(left: &Path, right: &Path) -> Result { Ok(canonical(left)? == canonical(right)? || crate::same_existing_file(left, right)?) } -pub fn validate_bifrost_persona_feedback_source( - source_store: &Path, - trust_anchor_path: &Path, - expected_runtime_id: &str, - expected_repository: &str, - expected_persona_id: &str, -) -> Result { - Ok(validated_bifrost_persona_feedback_deliveries( - source_store, - trust_anchor_path, - expected_runtime_id, - expected_repository, - expected_persona_id, - )? - .1 - .len()) -} - fn validated_bifrost_persona_feedback_deliveries( source_store: &Path, trust_anchor_path: &Path, @@ -784,134 +679,6 @@ mod tests { Ok(admission) } - #[test] - fn applies_authenticated_cultnet_snapshot_as_an_atomic_delivery_only_source() -> Result<()> { - let temp = tempfile::tempdir()?; - let signer = crate::enroll_host_identity_at(&temp.path().join("bifrost.cc"))?; - let anchor = crate::export_host_identity_trust_anchor( - &signer, - &temp.path().join("unused-anchor-store.cc"), - )?; - let anchor_path = temp.path().join("bifrost-anchor.msgpack"); - std::fs::write(&anchor_path, rmp_serde::to_vec(&anchor)?)?; - let delivery = signed_delivery(&signer, "epiphany")?; - let snapshot = CultNetMessage::SnapshotResponseRaw { - message_id: "bifrost-export-1".into(), - documents: vec![ - cultnet_rs::CultNetRawDocumentRecord { - schema_id: BIFROST_PERSONA_FEEDBACK_ADMISSION_SCHEMA_VERSION.into(), - record_key: delivery.admission_id.clone(), - stored_at: "2026-08-06T00:00:00Z".into(), - payload_encoding: CultNetRawPayloadEncoding::Messagepack, - payload: rmp_serde::to_vec(&delivery)?, - source_runtime_id: Some("bifrost-yggdrasil".into()), - source_agent_id: Some(delivery.provider_identity_id.clone()), - source_role: Some("bifrost-persona-feedback".into()), - tags: Some(vec!["cultnet.transport.snapshot.v0".into()]), - }, - cultnet_rs::CultNetRawDocumentRecord { - schema_id: BIFROST_PERSONA_FEEDBACK_RECEIPT_SCHEMA_VERSION.into(), - record_key: "receipt-1".into(), - stored_at: "2026-08-06T00:00:00Z".into(), - payload_encoding: CultNetRawPayloadEncoding::Messagepack, - payload: rmp_serde::to_vec(&(1_u8,))?, - source_runtime_id: Some("bifrost-yggdrasil".into()), - source_agent_id: None, - source_role: Some("bifrost-persona-feedback".into()), - tags: None, - }, - ], - }; - let snapshot_path = temp.path().join("export.msgpack"); - std::fs::write( - &snapshot_path, - cultnet_rs::encode_cultnet_message_to_vec( - &snapshot, - CultNetWireContract::CultNetSchemaV0, - )?, - )?; - let source_store = temp.path().join("crossed-deliveries.cc"); - - assert_eq!( - apply_bifrost_persona_feedback_snapshot( - &snapshot_path, - &source_store, - &anchor_path, - "epiphany-yggdrasil", - "GameCult/Epiphany", - "epiphany", - )?, - 1 - ); - assert_eq!( - validate_bifrost_persona_feedback_source( - &source_store, - &anchor_path, - "epiphany-yggdrasil", - "GameCult/Epiphany", - "epiphany", - )?, - 1 - ); - let entries = - SingleFileMessagePackBackingStore::new(&source_store).pull_all_read_only_snapshot()?; - assert_eq!(entries.len(), 1); - assert_eq!(entries[0].r#type, BIFROST_PERSONA_FEEDBACK_DELIVERY_TYPE); - Ok(()) - } - - #[test] - fn refuses_invalid_snapshot_before_replacing_the_crossing_source() -> Result<()> { - let temp = tempfile::tempdir()?; - let signer = crate::enroll_host_identity_at(&temp.path().join("bifrost.cc"))?; - let anchor = crate::export_host_identity_trust_anchor( - &signer, - &temp.path().join("unused-anchor-store.cc"), - )?; - let anchor_path = temp.path().join("bifrost-anchor.msgpack"); - std::fs::write(&anchor_path, rmp_serde::to_vec(&anchor)?)?; - let source_store = temp.path().join("crossed-deliveries.cc"); - std::fs::write(&source_store, b"previous-good-source")?; - let before = std::fs::read(&source_store)?; - let mut delivery = signed_delivery(&signer, "epiphany")?; - delivery.packet.feedback_text = "unsigned substitution".into(); - let snapshot = CultNetMessage::SnapshotResponseRaw { - message_id: "bifrost-export-invalid".into(), - documents: vec![cultnet_rs::CultNetRawDocumentRecord { - schema_id: BIFROST_PERSONA_FEEDBACK_ADMISSION_SCHEMA_VERSION.into(), - record_key: delivery.admission_id.clone(), - stored_at: "2026-08-06T00:00:00Z".into(), - payload_encoding: CultNetRawPayloadEncoding::Messagepack, - payload: rmp_serde::to_vec(&delivery)?, - source_runtime_id: Some("bifrost-yggdrasil".into()), - source_agent_id: None, - source_role: Some("bifrost-persona-feedback".into()), - tags: None, - }], - }; - let snapshot_path = temp.path().join("invalid.msgpack"); - std::fs::write( - &snapshot_path, - cultnet_rs::encode_cultnet_message_to_vec( - &snapshot, - CultNetWireContract::CultNetSchemaV0, - )?, - )?; - assert!( - apply_bifrost_persona_feedback_snapshot( - &snapshot_path, - &source_store, - &anchor_path, - "epiphany-yggdrasil", - "GameCult/Epiphany", - "epiphany", - ) - .is_err() - ); - assert_eq!(std::fs::read(&source_store)?, before); - Ok(()) - } - #[test] fn admits_exact_authenticated_delivery_as_pressure_only() -> Result<()> { let temp = tempfile::tempdir()?; diff --git a/epiphany-release-construction/src/lib.rs b/epiphany-release-construction/src/lib.rs index 8707d179..357a2c4b 100644 --- a/epiphany-release-construction/src/lib.rs +++ b/epiphany-release-construction/src/lib.rs @@ -96,10 +96,6 @@ pub fn required_packaged_release_binaries(target_triple: &str) -> Vec<(&'static ("repository-body", file_name("epiphany-repository-body")), ("host-identity", file_name("epiphany-host-identity")), ("swarm", file_name("epiphany-swarm")), - ( - "persona-feedback-ingress", - file_name("epiphany-persona-feedback-ingress"), - ), ("persona-service", file_name("epiphany-persona-service")), ( "persona-discord-permit",