use std::path::Path;
use super::Result;
use super::event::ExecutionEvent;
use super::store::ExecutionLedgerStore;
const LEGACY_TASK_ID: &str = "legacy-savings-ledger";
const LEGACY_TRACE_ID: &str = "legacy-savings-ledger";
pub fn migrate_from_savings_ledger() -> Result<usize> {
let Some(source_path) = crate::core::savings_ledger::store::default_path() else {
return Ok(0);
};
let destination = ExecutionLedgerStore::from_default()?;
migrate_from_savings_ledger_at(&source_path, &destination, LEGACY_TASK_ID, LEGACY_TRACE_ID)
}
pub fn migrate_from_savings_ledger_at(
source_path: &Path,
destination: &ExecutionLedgerStore,
task_id: &str,
trace_id: &str,
) -> Result<usize> {
let source_events = crate::core::savings_ledger::store::load(source_path);
let mut migrated = 0;
for (index, source) in source_events.iter().enumerate() {
let evidence_ref = format!("savings-ledger:sha256:{}", source.entry_hash);
let plan_id = format!("legacy-savings-plan:{index}");
let event_trace_id = source
.trace_id
.as_deref()
.filter(|value| !value.is_empty())
.unwrap_or(trace_id)
.to_owned();
destination.append(ExecutionEvent::PlanCreated {
task_id: task_id.to_owned(),
trace_id: event_trace_id.clone(),
plan_id: plan_id.clone(),
plan_ref: evidence_ref,
timestamp: source.ts.clone(),
sequence_number: 0,
prev_hash: String::new(),
})?;
destination.append(ExecutionEvent::ModelInvoked {
task_id: task_id.to_owned(),
trace_id: event_trace_id,
plan_id,
model: source.model_id.clone(),
provider: "savings-ledger".to_owned(),
tokens_in: source.actual_tokens,
tokens_out: source.response_delivered_tokens.unwrap_or(0),
latency_ms: 0,
timestamp: source.ts.clone(),
sequence_number: 0,
prev_hash: String::new(),
})?;
migrated += 1;
}
Ok(migrated)
}