diff --git a/epiphany-core/src/bin/epiphany-daemon-supervisor.rs b/epiphany-core/src/bin/epiphany-daemon-supervisor.rs index f4ab81ec..bca5ef5e 100644 --- a/epiphany-core/src/bin/epiphany-daemon-supervisor.rs +++ b/epiphany-core/src/bin/epiphany-daemon-supervisor.rs @@ -17,15 +17,14 @@ use epiphany_core::EpiphanyProcessObservation as ProcessObservation; use epiphany_core::authenticate_epiphany_cultmesh_semantic_projector_launch; use epiphany_core::authenticate_resident_provider; use epiphany_core::idunn_recover_memory_semantic_projection_from_cultmesh; +use epiphany_core::load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service; use epiphany_core::load_epiphany_cultmesh_cluster_topology; -use epiphany_core::load_epiphany_cultmesh_daemon_service_lifecycle_receipts; use epiphany_core::load_epiphany_cultmesh_managed_service_policies; use epiphany_core::load_epiphany_cultmesh_managed_service_policy; use epiphany_core::load_epiphany_cultmesh_managed_service_policy_with_digest; use epiphany_core::load_epiphany_cultmesh_swarm_brake; use epiphany_core::load_epiphany_packaged_release; use epiphany_core::load_latest_epiphany_cultmesh_daemon_heartbeat; -use epiphany_core::load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service; use epiphany_core::observe_native_process as observe_process; use epiphany_core::runtime_modeling_semantic_projection_input; use epiphany_core::write_epiphany_cultmesh_daemon_service_lifecycle_receipt; @@ -556,7 +555,7 @@ fn windows_quote_argv(arg: &str) -> String { } fn semantic_projector_service_status(args: Args) -> Result<()> { - let receipt = load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( + let receipt = load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( &args.store, args.runtime_id.clone(), SEMANTIC_PROJECTOR_SERVICE_ID, @@ -954,7 +953,7 @@ fn managed_service_lineage( }, ); } - let Some(receipt) = load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( + let Some(receipt) = load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( &args.store, args.runtime_id.clone(), &policy.service_id, @@ -1652,14 +1651,12 @@ fn managed_service_reconcile(mut args: Args) -> Result<()> { if policy.service_id == WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID { return reconcile_workspace_coverage_projector(args, policy); } - let latest = load_epiphany_cultmesh_daemon_service_lifecycle_receipts( + let current = load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( &args.store, args.runtime_id.clone(), - )? - .into_iter() - .filter(|receipt| receipt.service_id == args.service_id) - .max_by(|left, right| left.started_at_utc.cmp(&right.started_at_utc)); - let mut observation = latest + &args.service_id, + )?; + let mut observation = current .as_ref() .and_then(|receipt| receipt.process_id) .map(observe_process) @@ -1672,7 +1669,7 @@ fn managed_service_reconcile(mut args: Args) -> Result<()> { })?; if let Some(identity) = replacement_process_identity( &lineage, - latest + current .as_ref() .context("alive managed service has no lifecycle receipt")?, )? { @@ -1701,7 +1698,7 @@ fn managed_service_reconcile(mut args: Args) -> Result<()> { "schemaVersion": "epiphany.cultmesh.managed_service_reconcile.v0", "status": "observed-alive", "serviceId": policy.service_id, - "processId": latest.as_ref().and_then(|receipt| receipt.process_id), + "processId": current.as_ref().and_then(|receipt| receipt.process_id), "processObservation": observation.label(), "restarted": false, "privateStateExposed": false, @@ -1710,7 +1707,7 @@ fn managed_service_reconcile(mut args: Args) -> Result<()> { return Ok(()); } if !args.force && policy.cooldown_seconds > 0 { - if let Some(started) = latest + if let Some(started) = current .as_ref() .and_then(|receipt| DateTime::parse_from_rfc3339(&receipt.started_at_utc).ok()) { diff --git a/epiphany-core/src/cultmesh_integration.rs b/epiphany-core/src/cultmesh_integration.rs index 28ceac15..98f8245a 100644 --- a/epiphany-core/src/cultmesh_integration.rs +++ b/epiphany-core/src/cultmesh_integration.rs @@ -26,7 +26,6 @@ use anyhow::Context; use anyhow::Result; use anyhow::anyhow; use chrono::DateTime; -use chrono::FixedOffset; use chrono::Utc; use cultcache_rs::CacheBackingStore; use cultcache_rs::DatabaseEntry; @@ -52,8 +51,6 @@ pub const EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_TYPE: &str = "epiphany.cultmesh.daemon_service_lifecycle_receipt"; pub const EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION: &str = "epiphany.cultmesh.daemon_service_lifecycle_receipt.v2"; -pub const EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY: &str = - "epiphany-local/daemon-service-lifecycle-receipt/latest"; pub const EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_TYPE: &str = "epiphany.cultmesh.managed_service_policy"; pub const EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION: &str = @@ -520,8 +517,6 @@ pub struct EpiphanyLocalVerseContext { pub verse_policies: Vec, pub global_room_policies: Vec, pub cluster_topology: Vec, - pub latest_daemon_service_lifecycle_receipt: - Option, pub swarm_brake: Option, pub arrival_latest_bifrost_body_change_publication_intent: Option, @@ -809,46 +804,15 @@ pub fn write_epiphany_cultmesh_daemon_service_lifecycle_receipt( expected.push(policy_envelope.clone()); replacements.push(policy_envelope); } - let current_latest = node.get::( - EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY, - )?; - if current_latest.as_ref().is_none_or(|current| { - daemon_service_lifecycle_event_key(&written) >= daemon_service_lifecycle_event_key(current) - }) { - if let Some(envelope) = node - .cache() - .get_envelope::( - EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY, - )? - { - expected.push(envelope); - } - replacements.push( - node.cache() - .prepare_entry( - EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY, - &written, - )? - .0, - ); - } - let service_latest_key = - epiphany_cultmesh_daemon_service_lifecycle_receipt_latest_key(&written.service_id); - let current_service_latest = - node.get::(&service_latest_key)?; - if current_service_latest.as_ref().is_none_or(|current| { - daemon_service_lifecycle_event_key(&written) >= daemon_service_lifecycle_event_key(current) - }) { - if let Some(envelope) = node - .cache() - .get_envelope::( - &service_latest_key, - )? - { - expected.push(envelope); - } - replacements.push(node.cache().prepare_entry(&service_latest_key, &written)?.0); + let service_current_key = + epiphany_cultmesh_daemon_service_lifecycle_receipt_current_key(&written.service_id); + if let Some(envelope) = node + .cache() + .get_envelope::(&service_current_key)? + { + expected.push(envelope); } + replacements.push(node.cache().prepare_entry(&service_current_key, &written)?.0); let backing = SingleFileMessagePackBackingStore::new(store_path); if backing.compare_and_swap_batch(&expected, replacements)? { return Ok(written); @@ -863,7 +827,7 @@ pub fn write_epiphany_cultmesh_daemon_service_lifecycle_receipt( written.receipt_id )), None => Err(anyhow!( - "daemon service lifecycle receipt CAS lost concurrent latest-state race" + "daemon service lifecycle receipt CAS lost concurrent current-state race" )), } } @@ -928,37 +892,13 @@ pub fn authenticate_epiphany_cultmesh_semantic_projector_launch( Ok(receipt) } -pub fn load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt( - store_path: impl AsRef, - runtime_id: impl Into, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - node.get(EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY) -} - -pub fn load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( +pub fn load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( store_path: impl AsRef, runtime_id: impl Into, service_id: &str, ) -> Result> { let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - node.get(&epiphany_cultmesh_daemon_service_lifecycle_receipt_latest_key(service_id)) -} - -pub fn load_epiphany_cultmesh_daemon_service_lifecycle_receipts( - store_path: impl AsRef, - runtime_id: impl Into, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - Ok(node - .get_all_with_keys::()? - .into_iter() - .filter(|(key, _)| { - key != EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY - && !key.starts_with("epiphany-local/daemon-service-lifecycle-receipt/latest/") - }) - .map(|(_, receipt)| receipt) - .collect()) + node.get(&epiphany_cultmesh_daemon_service_lifecycle_receipt_current_key(service_id)) } pub fn write_epiphany_cultmesh_semantic_projector_service_policy( @@ -1437,22 +1377,6 @@ fn validate_semantic_projector_launch_receipt( Ok(()) } -fn daemon_service_lifecycle_event_key( - receipt: &EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, -) -> (DateTime, &str) { - let event_time = receipt - .completed_at_utc - .as_deref() - .map(DateTime::parse_from_rfc3339) - .transpose() - .expect("validated lifecycle completion timestamp") - .unwrap_or_else(|| { - DateTime::parse_from_rfc3339(&receipt.started_at_utc) - .expect("validated lifecycle start timestamp") - }); - (event_time, receipt.receipt_id.as_str()) -} - pub fn epiphany_cultmesh_bifrost_body_change_publication_intent( intent_id: impl Into, source_cluster_id: impl Into, @@ -1838,8 +1762,6 @@ pub fn query_epiphany_local_verse_context( verse_policies, global_room_policies, cluster_topology, - latest_daemon_service_lifecycle_receipt: node - .get(EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY)?, swarm_brake: node.get(EPIPHANY_CULTMESH_SWARM_BRAKE_KEY)?, arrival_latest_bifrost_body_change_publication_intent: node .get(EPIPHANY_CULTMESH_BIFROST_BODY_CHANGE_PUBLICATION_INTENT_ARRIVAL_LATEST_KEY)?, @@ -1884,8 +1806,8 @@ fn epiphany_cultmesh_daemon_service_lifecycle_receipt_key(receipt_id: &str) -> S format!("epiphany-local/daemon-service-lifecycle-receipt/{receipt_id}") } -fn epiphany_cultmesh_daemon_service_lifecycle_receipt_latest_key(service_id: &str) -> String { - format!("epiphany-local/daemon-service-lifecycle-receipt/latest/{service_id}") +fn epiphany_cultmesh_daemon_service_lifecycle_receipt_current_key(service_id: &str) -> String { + format!("epiphany-local/daemon-service-lifecycle-receipt/current/{service_id}") } fn epiphany_cultmesh_managed_service_policy_key(service_id: &str) -> String { @@ -3085,98 +3007,6 @@ mod tests { Ok(()) } - #[test] - fn service_lifecycle_receipt_history_excludes_latest_mirror() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("epiphany-service-lifecycle.ccmp"); - let first = EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - .to_string(), - receipt_id: "service-lifecycle-first".to_string(), - service_id: "epiphany-daemon-supervisor-service".to_string(), - scheduler_id: "epiphany-daemon-supervisor".to_string(), - runtime_id: "epiphany-test".to_string(), - daemon_selector: "epiphany-daemon-supervisor".to_string(), - action: "windows-service-execution-audit".to_string(), - status: "incomplete".to_string(), - command: "epiphany-daemon-supervisor".to_string(), - args: vec!["windows-service-execution-audit".to_string()], - cwd: Some("E:/Projects/EpiphanyAgent".to_string()), - process_id: None, - exit_code: Some(0), - started_at_utc: "2026-06-18T00:00:00Z".to_string(), - completed_at_utc: Some("2026-06-18T00:00:01Z".to_string()), - operator_artifact_ref: "artifact://service-lifecycle/first".to_string(), - private_state_exposed: false, - notes: Vec::new(), - executable_sha256: "sha256-test-projector".into(), - preflight_witness_id: String::new(), - required_document_types: Vec::new(), - schema_preflight_passed: false, - schema_catalog_sha256: String::new(), - managed_policy_id: String::new(), - managed_policy_digest: String::new(), - provider_daemon_id: String::new(), - startup_correlation_id: String::new(), - process_creation_token: 0, - process_created_at_rfc3339: None, - process_executable_path: String::new(), - }; - let mut second = first.clone(); - second.receipt_id = "service-lifecycle-second".to_string(); - second.status = "written".to_string(); - second.action = "windows-service-execution-runbook".to_string(); - second.started_at_utc = "2026-06-18T00:01:00Z".to_string(); - second.completed_at_utc = Some("2026-06-18T00:01:01Z".to_string()); - second.operator_artifact_ref = "artifact://service-lifecycle/second".to_string(); - - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test", - first.clone(), - )?; - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test", - second.clone(), - )?; - - let receipts = - load_epiphany_cultmesh_daemon_service_lifecycle_receipts(&store, "epiphany-test")?; - let mut ids = receipts - .iter() - .map(|receipt| receipt.receipt_id.as_str()) - .collect::>(); - ids.sort_unstable(); - assert_eq!( - ids, - vec!["service-lifecycle-first", "service-lifecycle-second"] - ); - assert_eq!( - load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test" - )?, - Some(second.clone()) - ); - - let mut delayed_first = first.clone(); - delayed_first.receipt_id = "service-lifecycle-delayed-first".to_string(); - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test", - delayed_first, - )?; - assert_eq!( - load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test" - )?, - Some(second) - ); - Ok(()) - } - #[test] fn service_lifecycle_receipt_refuses_invalid_or_reversed_time() -> Result<()> { let temp = tempfile::tempdir()?; @@ -3235,9 +3065,10 @@ mod tests { .is_err() ); assert!( - load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt( + load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( &store, - "epiphany-test" + "epiphany-test", + "epiphany-daemon-supervisor-service", )? .is_none() ); @@ -3266,40 +3097,6 @@ mod tests { Ok(()) } - #[test] - fn swarm_brake_round_trips_and_projects_status() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("epiphany-swarm-brake.ccmp"); - seed_epiphany_local_verse_context( - &store, - "epiphany-test", - "2026-06-17T00:00:00Z", - "repo:C:/fixture/Epiphany", - )?; - - let brake = load_epiphany_cultmesh_swarm_brake(&store, "epiphany-test")? - .expect("seeded swarm brake exists"); - assert_eq!(brake.status, "released"); - assert_eq!(brake.scope, "swarm"); - assert!(!brake.private_state_exposed); - assert!( - brake - .affected_clusters - .iter() - .any(|cluster| cluster == "epiphany.cluster.persona") - ); - - let context = query_epiphany_local_verse_context(&store, "epiphany-test")?; - assert_eq!( - context - .swarm_brake - .as_ref() - .map(|brake| brake.status.as_str()), - Some("released") - ); - Ok(()) - } - #[test] fn canonical_engagement_protects_daemon_lifecycle_actuation() -> Result<()> { let temp = tempfile::tempdir()?; diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index 290f1fb5..cf00b05b 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -145,7 +145,6 @@ pub use cultmesh_integration::EPIPHANY_CULTMESH_BIFROST_GITHUB_PUBLICATION_RECEI pub use cultmesh_integration::EPIPHANY_CULTMESH_BIFROST_GITHUB_PUBLICATION_RECEIPT_TYPE; pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION; pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_TYPE; -pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_LATEST_KEY; pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION; pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_TYPE; pub use cultmesh_integration::EPIPHANY_CULTMESH_GLOBAL_TIER; @@ -194,15 +193,13 @@ pub use cultmesh_integration::idunn_recover_memory_semantic_projection_from_cult pub use cultmesh_integration::load_epiphany_cultmesh_cluster_topology; pub use cultmesh_integration::load_epiphany_cultmesh_daemon_heartbeat_event; pub use cultmesh_integration::load_epiphany_cultmesh_daemon_service_lifecycle_receipt; -pub use cultmesh_integration::load_epiphany_cultmesh_daemon_service_lifecycle_receipts; pub use cultmesh_integration::load_epiphany_cultmesh_managed_service_policies; pub use cultmesh_integration::load_epiphany_cultmesh_managed_service_policy; pub use cultmesh_integration::load_epiphany_cultmesh_managed_service_policy_with_digest; pub use cultmesh_integration::load_epiphany_cultmesh_semantic_projection_health; pub use cultmesh_integration::load_epiphany_cultmesh_swarm_brake; pub use cultmesh_integration::load_latest_epiphany_cultmesh_daemon_heartbeat; -pub use cultmesh_integration::load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt; -pub use cultmesh_integration::load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service; +pub use cultmesh_integration::load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service; pub use cultmesh_integration::open_epiphany_cultmesh_node; pub use cultmesh_integration::publish_epiphany_cultmesh_semantic_projection_health; pub use cultmesh_integration::query_epiphany_local_verse_context;