use common_contracts::messages::TaskType; pub struct IOBinder; impl IOBinder { pub fn new() -> Self { Self } pub fn allocate_output_path( &self, task_type: TaskType, symbol: &str, task_id: &str, display_name: Option<&str>, ) -> String { // Convention based paths: // DataFetch: raw/{provider_id}/{symbol} // DataProcessing: processed/{processor_id}/{symbol} // Analysis: analysis/{module_name_or_id}/{symbol}.md let clean_task_id = task_id.split(':').last().unwrap_or(task_id); match task_type { TaskType::DataFetch => format!("raw/{}/{}", clean_task_id, symbol), TaskType::DataProcessing => format!("processed/{}/{}", clean_task_id, symbol), TaskType::Analysis => { let folder_name = if let Some(name) = display_name { self.sanitize_path_segment(name) } else { clean_task_id.to_string() }; format!("analysis/{}/{}.md", folder_name, symbol) }, } } pub fn allocate_trace_path( &self, task_type: TaskType, symbol: &str, task_id: &str, display_name: Option<&str>, ) -> String { let clean_task_id = task_id.split(':').last().unwrap_or(task_id); match task_type { TaskType::Analysis => { let folder_name = if let Some(name) = display_name { self.sanitize_path_segment(name) } else { clean_task_id.to_string() }; format!("analysis/{}/{}_trace.md", folder_name, symbol) }, _ => format!("debug/{}/{}_trace.md", clean_task_id, symbol), } } fn sanitize_path_segment(&self, name: &str) -> String { name.replace('/', "_") .replace('\\', "_") .replace(':', "_") .replace('"', "_") .replace('<', "_") .replace('>', "_") .replace('|', "_") .replace('?', "_") .replace('*', "_") .trim() .to_string() } }