lean_ctx/core/execution_ledger/
migration.rs1use std::path::Path;
7
8use super::Result;
9use super::event::ExecutionEvent;
10use super::store::ExecutionLedgerStore;
11
12const LEGACY_TASK_ID: &str = "legacy-savings-ledger";
13const LEGACY_TRACE_ID: &str = "legacy-savings-ledger";
14
15pub fn migrate_from_savings_ledger() -> Result<usize> {
21 let Some(source_path) = crate::core::savings_ledger::store::default_path() else {
22 return Ok(0);
23 };
24 let destination = ExecutionLedgerStore::from_default()?;
25 migrate_from_savings_ledger_at(&source_path, &destination, LEGACY_TASK_ID, LEGACY_TRACE_ID)
26}
27
28pub fn migrate_from_savings_ledger_at(
34 source_path: &Path,
35 destination: &ExecutionLedgerStore,
36 task_id: &str,
37 trace_id: &str,
38) -> Result<usize> {
39 let source_events = crate::core::savings_ledger::store::load(source_path);
40 if source_events.is_empty() {
41 return Ok(0);
42 }
43 destination.append(ExecutionEvent::TaskStarted {
44 task_id: task_id.to_owned(),
45 trace_id: trace_id.to_owned(),
46 envelope_ref: "legacy:savings-ledger".to_owned(),
47 timestamp: "1970-01-01T00:00:00Z".to_owned(),
48 sequence_number: 0,
49 prev_hash: String::new(),
50 })?;
51 const LEGACY_PLAN_ID: &str = "legacy-savings-plan";
52 destination.append_if_new(ExecutionEvent::PlanCreated {
53 task_id: task_id.to_owned(),
54 trace_id: trace_id.to_owned(),
55 plan_id: LEGACY_PLAN_ID.to_owned(),
56 plan_ref: "legacy:savings-ledger".to_owned(),
57 timestamp: "1970-01-01T00:00:00Z".to_owned(),
58 sequence_number: 0,
59 prev_hash: String::new(),
60 })?;
61 let mut migrated = 0;
62
63 for source in &source_events {
64 let model_added = destination.append_if_new(ExecutionEvent::ModelInvoked {
65 task_id: task_id.to_owned(),
66 trace_id: trace_id.to_owned(),
67 plan_id: LEGACY_PLAN_ID.to_owned(),
68 invocation_id: format!("legacy-savings-invocation:{}", source.entry_hash),
69 invocation_ref: format!("savings-ledger:sha256:{}", source.entry_hash),
70 model: source.model_id.clone(),
71 provider: "savings-ledger".to_owned(),
72 tokens_in: source.actual_tokens,
73 tokens_out: source.response_delivered_tokens.unwrap_or(0),
74 latency_ms: 0,
75 timestamp: source.ts.clone(),
76 sequence_number: 0,
77 prev_hash: String::new(),
78 })?;
79 migrated += usize::from(model_added);
80 }
81
82 Ok(migrated)
83}