From 2bc2e0890f4599e9f4762793d84e0235f27a3bd7 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 6 May 2026 13:58:22 +0100 Subject: [PATCH] Remove heartbeat JSON migration hatches --- .../src/bin/epiphany-heartbeat-store.rs | 46 +---- epiphany-core/src/heartbeat_state.rs | 187 ------------------ epiphany-core/src/lib.rs | 4 - state/ledgers.msgpack | Bin 49693 -> 49941 bytes 4 files changed, 1 insertion(+), 236 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-heartbeat-store.rs b/epiphany-core/src/bin/epiphany-heartbeat-store.rs index 42c3821c..a7a7567a 100644 --- a/epiphany-core/src/bin/epiphany-heartbeat-store.rs +++ b/epiphany-core/src/bin/epiphany-heartbeat-store.rs @@ -8,10 +8,8 @@ use epiphany_core::complete_heartbeat_store; use epiphany_core::heartbeat_status_projection; use epiphany_core::initialize_heartbeat_store; use epiphany_core::load_heartbeat_state_entry; -use epiphany_core::migrate_heartbeat_json_to_cultcache; use epiphany_core::tick_heartbeat_store; use epiphany_core::validate_agent_memory_store; -use epiphany_core::write_heartbeat_json_projection; use std::env; use std::fs; use std::path::Path; @@ -23,9 +21,7 @@ fn main() -> Result<()> { let Some(command) = args.next() else { return usage(); }; - let mut json_path: Option = None; let mut store_path: Option = None; - let mut projection_path: Option = None; let mut artifact_dir: Option = None; let mut target_heartbeat_rate = 1.0_f64; let mut coordinator_action: Option = None; @@ -42,9 +38,7 @@ fn main() -> Result<()> { while let Some(arg) = args.next() { match arg.as_str() { - "--json" => json_path = Some(next_path(&mut args, "--json")?), "--store" => store_path = Some(next_path(&mut args, "--store")?), - "--projection" => projection_path = Some(next_path(&mut args, "--projection")?), "--artifact-dir" => artifact_dir = Some(next_path(&mut args, "--artifact-dir")?), "--target-heartbeat-rate" => { target_heartbeat_rate = next_value(&mut args, "--target-heartbeat-rate")?.parse()? @@ -129,44 +123,6 @@ fn main() -> Result<()> { )?; println!("{}", result); } - "migrate-json" => { - let json_path = json_path.ok_or_else(|| anyhow!("migrate-json requires --json"))?; - let store_path = store_path.ok_or_else(|| anyhow!("migrate-json requires --store"))?; - let state = migrate_heartbeat_json_to_cultcache(&json_path, &store_path)?; - if let Some(projection_path) = projection_path { - write_heartbeat_json_projection(&store_path, projection_path)?; - } - println!( - "{}", - serde_json::json!({ - "ok": true, - "command": "migrate-json", - "json": json_path, - "store": store_path, - "schemaVersion": state.schema_version, - "participants": state.participants.len(), - "history": state.history.len(), - }) - ); - } - "project" => { - let store_path = store_path.ok_or_else(|| anyhow!("project requires --store"))?; - let projection_path = - projection_path.ok_or_else(|| anyhow!("project requires --projection"))?; - let state = write_heartbeat_json_projection(&store_path, &projection_path)?; - println!( - "{}", - serde_json::json!({ - "ok": true, - "command": "project", - "store": store_path, - "projection": projection_path, - "schemaVersion": state.schema_version, - "participants": state.participants.len(), - "history": state.history.len(), - }) - ); - } "status" => { let store_path = store_path.ok_or_else(|| anyhow!("status requires --store"))?; if let Some(artifact_dir) = artifact_dir { @@ -221,7 +177,7 @@ fn next_value(args: &mut impl Iterator, name: &str) -> Result Result<()> { Err(anyhow!( - "usage: epiphany-heartbeat-store init --store \n epiphany-heartbeat-store tick --store --artifact-dir [--coordinator-action ] [--agent-store --apply-rumination] [--defer-completion]\n epiphany-heartbeat-store complete --store --artifact-dir --role [--action-id ]\n epiphany-heartbeat-store status --store [--artifact-dir ]\n epiphany-heartbeat-store migrate-json --json --store [--projection ]\n epiphany-heartbeat-store project --store --projection \n epiphany-heartbeat-store smoke [--agent-store ]" + "usage: epiphany-heartbeat-store init --store \n epiphany-heartbeat-store tick --store --artifact-dir [--coordinator-action ] [--agent-store --apply-rumination] [--defer-completion]\n epiphany-heartbeat-store complete --store --artifact-dir --role [--action-id ]\n epiphany-heartbeat-store status --store [--artifact-dir ]\n epiphany-heartbeat-store smoke [--agent-store ]" )) } diff --git a/epiphany-core/src/heartbeat_state.rs b/epiphany-core/src/heartbeat_state.rs index e2c7b5f5..e2360fe8 100644 --- a/epiphany-core/src/heartbeat_state.rs +++ b/epiphany-core/src/heartbeat_state.rs @@ -176,61 +176,6 @@ pub struct HeartbeatCompleteOptions { pub action_id: Option, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -struct EpiphanyHeartbeatStateProjection { - pub schema_version: String, - pub target_heartbeat_rate: f64, - pub scene_clock: f64, - pub selection_policy: HeartbeatSelectionPolicy, - pub pacing_policy: HeartbeatPacingPolicy, - pub participants: Vec, - pub history: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub sleep_cycle: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub memory_resonance: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub incubation: Option, - #[serde(flatten)] - pub extra: BTreeMap, -} - -impl From for EpiphanyHeartbeatStateEntry { - fn from(value: EpiphanyHeartbeatStateProjection) -> Self { - Self { - schema_version: value.schema_version, - target_heartbeat_rate: value.target_heartbeat_rate, - scene_clock: value.scene_clock, - selection_policy: value.selection_policy, - pacing_policy: value.pacing_policy, - participants: value.participants, - history: value.history, - sleep_cycle: value.sleep_cycle, - memory_resonance: value.memory_resonance, - incubation: value.incubation, - extra: value.extra, - } - } -} - -impl From for EpiphanyHeartbeatStateProjection { - fn from(value: EpiphanyHeartbeatStateEntry) -> Self { - Self { - schema_version: value.schema_version, - target_heartbeat_rate: value.target_heartbeat_rate, - scene_clock: value.scene_clock, - selection_policy: value.selection_policy, - pacing_policy: value.pacing_policy, - participants: value.participants, - history: value.history, - sleep_cycle: value.sleep_cycle, - memory_resonance: value.memory_resonance, - incubation: value.incubation, - extra: value.extra, - } - } -} - pub fn heartbeat_state_cache(store_path: impl AsRef) -> Result { let mut cache = CultCache::new(); cache.register_entry_type::()?; @@ -255,59 +200,6 @@ pub fn write_heartbeat_state_entry( cache.put(HEARTBEAT_STATE_KEY, state) } -pub fn migrate_heartbeat_json_to_cultcache( - json_path: impl AsRef, - store_path: impl AsRef, -) -> Result { - let state = read_heartbeat_json_projection(json_path)?; - write_heartbeat_state_entry(store_path, &state) -} - -pub fn write_heartbeat_json_projection( - store_path: impl AsRef, - json_path: impl AsRef, -) -> Result { - let state = load_heartbeat_state_entry(store_path.as_ref())?.ok_or_else(|| { - anyhow!( - "CultCache store {} has no heartbeat state entry", - store_path.as_ref().display() - ) - })?; - write_projection_json(json_path, &state)?; - Ok(state) -} - -pub fn read_heartbeat_json_projection( - json_path: impl AsRef, -) -> Result { - let path = json_path.as_ref(); - let raw = fs::read_to_string(path) - .with_context(|| format!("failed to read heartbeat JSON {}", path.display()))?; - let projection: EpiphanyHeartbeatStateProjection = serde_json::from_str(&raw) - .with_context(|| format!("failed to decode heartbeat JSON {}", path.display()))?; - let state = EpiphanyHeartbeatStateEntry::from(projection); - validate_heartbeat_state(&state)?; - Ok(state) -} - -pub fn write_projection_json( - json_path: impl AsRef, - state: &EpiphanyHeartbeatStateEntry, -) -> Result<()> { - validate_heartbeat_state(state)?; - let path = json_path.as_ref(); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent) - .with_context(|| format!("failed to create {}", parent.display()))?; - } - let projection = EpiphanyHeartbeatStateProjection::from(state.clone()); - let raw = serde_json::to_string_pretty(&projection) - .context("failed to encode heartbeat JSON projection")?; - fs::write(path, format!("{raw}\n")) - .with_context(|| format!("failed to write heartbeat JSON {}", path.display()))?; - Ok(()) -} - pub fn validate_heartbeat_state(state: &EpiphanyHeartbeatStateEntry) -> Result<()> { if state.schema_version != HEARTBEAT_STATE_SCHEMA_VERSION { return Err(anyhow!( @@ -1273,45 +1165,6 @@ mod tests { use super::*; use pretty_assertions::assert_eq; - #[test] - fn heartbeat_json_migrates_to_typed_cultcache_and_projects_back() -> Result<()> { - let temp = tempfile::tempdir()?; - let json_path = temp.path().join("heartbeats.json"); - let store_path = temp.path().join("heartbeats.msgpack"); - let projected_path = temp.path().join("heartbeats.projected.json"); - fs::write(&json_path, sample_json())?; - - let migrated = migrate_heartbeat_json_to_cultcache(&json_path, &store_path)?; - assert_eq!(migrated.schema_version, HEARTBEAT_STATE_SCHEMA_VERSION); - assert_eq!(migrated.participants[0].role_id, "coordinator"); - - let loaded = load_heartbeat_state_entry(&store_path)?.expect("persisted heartbeat state"); - assert_eq!(loaded, migrated); - - write_heartbeat_json_projection(&store_path, &projected_path)?; - let projected = read_heartbeat_json_projection(&projected_path)?; - assert_eq!(projected, migrated); - Ok(()) - } - - #[test] - fn live_heartbeat_json_shape_is_compatible_when_present() -> Result<()> { - let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../state/agent-heartbeats.json"); - if !path.exists() { - return Ok(()); - } - let state = read_heartbeat_json_projection(&path)?; - validate_heartbeat_state(&state)?; - assert!(state.participants.iter().any(|item| item.role_id == "face")); - assert!( - state - .participants - .iter() - .any(|item| item.role_id == "coordinator") - ); - Ok(()) - } - #[test] fn native_heartbeat_store_ticks_and_completes_without_json_state() -> Result<()> { let temp = tempfile::tempdir()?; @@ -1368,44 +1221,4 @@ mod tests { assert!(artifact_dir.join("native-work.completion.json").exists()); Ok(()) } - - fn sample_json() -> &'static str { - r#"{ - "schema_version": "epiphany.agent_heartbeat.v0", - "target_heartbeat_rate": 1.0, - "scene_clock": 0.0, - "selection_policy": { - "mode": "readiness_queue", - "reaction_precedence": true, - "minimum_speed": 0.2, - "tie_breakers": ["next_ready_at_asc"] - }, - "pacing_policy": { - "cooldown_starts_after_turn_completion": true, - "work_base_recovery": 6.0, - "idle_base_recovery": 2.0, - "sleep_heartbeat_rate_multiplier": 0.05, - "minimum_effective_rate": 0.001 - }, - "participants": [ - { - "agent_id": "epiphany.self", - "role_id": "coordinator", - "display_name": "Self", - "initiative_speed": 1.28, - "next_ready_at": 0.0, - "reaction_bias": 0.88, - "interrupt_threshold": 0.42, - "current_load": 0.0, - "status": "active", - "constraints": ["Routes and reviews."], - "last_action_id": null, - "last_woke_at": null, - "last_finished_at": null, - "pending_turn": null - } - ], - "history": [] -}"# - } } diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index cfc6255f..b81c4a24 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -44,13 +44,9 @@ pub use heartbeat_state::heartbeat_state_cache; pub use heartbeat_state::heartbeat_status_projection; pub use heartbeat_state::initialize_heartbeat_store; pub use heartbeat_state::load_heartbeat_state_entry; -pub use heartbeat_state::migrate_heartbeat_json_to_cultcache; -pub use heartbeat_state::read_heartbeat_json_projection; pub use heartbeat_state::tick_heartbeat_store; pub use heartbeat_state::validate_heartbeat_state; -pub use heartbeat_state::write_heartbeat_json_projection; pub use heartbeat_state::write_heartbeat_state_entry; -pub use heartbeat_state::write_projection_json; pub use promotion::EpiphanyPromotionDecision; pub use promotion::EpiphanyPromotionInput; pub use promotion::EpiphanyStateReplacementValidationInput; diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index c4c2f16e90c0d207fe186d5abf07a89260c2543b..9c5c6470e754896deaa15417f9c841b5deadb6d8 100644 GIT binary patch delta 165 zcmbQ+!aTK&d4eL-p}QNEr!g{CZr;V{dtmbCor3H}R;K1w#wL>k_iKvY-0ECfqL7iA zSX7dfnpmP+T#{duI$7$V?qsfs0z7&7