LINUS ROUND 1: Delete dead code (rust/c), generic Store[T], tests, slim main.go

- Removed rust-service/, c-runtime/, kafka stubs
- Generic Store[T] pattern with real tests
- Slimmed main.go from 324 to ~50 lines
- Added config, middleware, store, ledger, pdf tests
- Frontend SPA shell with router
- Binary: 15.5MB -> 12MB
This commit is contained in:
Bernt (LandveX AI)
2026-07-14 12:31:55 +00:00
parent 95b581e8c5
commit c2b10347b1
1100 changed files with 1544 additions and 7058 deletions
-173
View File
@@ -1,173 +0,0 @@
use dashmap::DashMap;
use rayon::prelude::*;
use serde_json::Value;
use std::collections::HashMap;
pub struct AnalyticsResult {
pub value: f64,
pub trend: f64,
pub breakdown: Vec<(String, f64)>,
}
pub struct AnalyticsEngine {
cache: DashMap<String, (AnalyticsResult, std::time::Instant)>,
}
impl AnalyticsEngine {
pub fn new() -> Self {
Self {
cache: DashMap::new(),
}
}
pub async fn query(&self, tenant_id: &str, metric: &str, period: &str) -> AnalyticsResult {
let cache_key = format!("{}:{}:{}", tenant_id, metric, period);
// Check cache (5 minute TTL)
if let Some(entry) = self.cache.get(&cache_key) {
if entry.value().1.elapsed().as_secs() < 300 {
return AnalyticsResult {
value: entry.value().0.value,
trend: entry.value().0.trend,
breakdown: entry.value().0.breakdown.clone(),
};
}
}
// Compute analytics (parallel processing for large datasets)
let result = self.compute_metric(tenant_id, metric, period).await;
// Cache result
self.cache.insert(cache_key, (result.clone(), std::time::Instant::now()));
result
}
async fn compute_metric(&self, tenant_id: &str, metric: &str, period: &str) -> AnalyticsResult {
match metric {
"mrr" => self.compute_mrr(tenant_id, period).await,
"arr" => self.compute_arr(tenant_id, period).await,
"churn" => self.compute_churn(tenant_id, period).await,
"ltv" => self.compute_ltv(tenant_id, period).await,
"cac" => self.compute_cac(tenant_id, period).await,
"pipeline_value" => self.compute_pipeline(tenant_id, period).await,
"conversion_rate" => self.compute_conversion(tenant_id, period).await,
_ => AnalyticsResult {
value: 0.0,
trend: 0.0,
breakdown: vec![],
},
}
}
async fn compute_mrr(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
// TODO: Query from database
// For now, return demo data
AnalyticsResult {
value: 53333.0,
trend: 0.05,
breakdown: vec![
("Subscriptions".to_string(), 45000.0),
("Add-ons".to_string(), 8333.0),
],
}
}
async fn compute_arr(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
AnalyticsResult {
value: 640000.0,
trend: 0.12,
breakdown: vec![
("Enterprise".to_string(), 400000.0),
("Professional".to_string(), 180000.0),
("Basic".to_string(), 60000.0),
],
}
}
async fn compute_churn(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
AnalyticsResult {
value: 0.02,
trend: -0.005,
breakdown: vec![
("Voluntary".to_string(), 0.012),
("Involuntary".to_string(), 0.008),
],
}
}
async fn compute_ltv(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
AnalyticsResult {
value: 125000.0,
trend: 0.08,
breakdown: vec![
("Enterprise".to_string(), 250000.0),
("Professional".to_string(), 100000.0),
("Basic".to_string(), 25000.0),
],
}
}
async fn compute_cac(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
AnalyticsResult {
value: 15000.0,
trend: -0.03,
breakdown: vec![
("Marketing".to_string(), 8000.0),
("Sales".to_string(), 5000.0),
("Partners".to_string(), 2000.0),
],
}
}
async fn compute_pipeline(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
AnalyticsResult {
value: 850000.0,
trend: 0.15,
breakdown: vec![
("Prospect".to_string(), 200000.0),
("Qualified".to_string(), 300000.0),
("Proposal".to_string(), 250000.0),
("Negotiation".to_string(), 100000.0),
],
}
}
async fn compute_conversion(&self, tenant_id: &str, period: &str) -> AnalyticsResult {
AnalyticsResult {
value: 0.25,
trend: 0.02,
breakdown: vec![
("Lead→Qualified".to_string(), 0.45),
("Qualified→Proposal".to_string(), 0.60),
("Proposal→Closed".to_string(), 0.35),
],
}
}
/// Batch process multiple metrics in parallel using Rayon
pub fn batch_compute(&self, tenant_id: &str, metrics: &[(&str, &str)]) -> Vec<AnalyticsResult> {
metrics
.par_iter()
.map(|(metric, period)| {
// Use tokio runtime to execute async code in parallel
let rt = tokio::runtime::Handle::try_current()
.unwrap_or_else(|_| tokio::runtime::Runtime::new().unwrap().handle().clone());
rt.block_on(async {
self.query(tenant_id, metric, period).await
})
})
.collect()
}
}
impl Clone for AnalyticsResult {
fn clone(&self) -> Self {
Self {
value: self.value,
trend: self.trend,
breakdown: self.breakdown.clone(),
}
}
}
-62
View File
@@ -1,62 +0,0 @@
// IPC module for Go-Rust communication via shared memory
// Placeholder for C FFI integration
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_void};
/// Initialize shared memory channel
pub fn init_channel(name: &str) -> Result<(), String> {
// TODO: Implement C FFI calls to libboc_ipc.so
println!("Initializing IPC channel: {}", name);
Ok(())
}
/// Send message via shared memory
pub fn send_message(channel: &str, data: &[u8]) -> Result<(), String> {
// TODO: Implement C FFI calls
println!("Sending {} bytes on channel: {}", data.len(), channel);
Ok(())
}
/// Receive message from shared memory
pub fn receive_message(channel: &str, timeout_ms: i32) -> Result<Vec<u8>, String> {
// TODO: Implement C FFI calls
println!("Receiving on channel: {} (timeout: {}ms)", channel, timeout_ms);
Ok(vec![])
}
/// C FFI wrapper for Go integration
#[no_mangle]
pub extern "C" fn boc_ipc_send(channel: *const c_char, data: *const c_void, len: c_int) -> c_int {
if channel.is_null() || data.is_null() {
return -1;
}
let channel_name = unsafe { CStr::from_ptr(channel).to_string_lossy() };
let data_slice = unsafe { std::slice::from_raw_parts(data as *const u8, len as usize) };
match send_message(&channel_name, data_slice) {
Ok(_) => 0,
Err(_) => -1,
}
}
#[no_mangle]
pub extern "C" fn boc_ipc_recv(channel: *const c_char, buf: *mut c_void, max_len: c_int, timeout_ms: c_int) -> c_int {
if channel.is_null() || buf.is_null() {
return -1;
}
let channel_name = unsafe { CStr::from_ptr(channel).to_string_lossy() };
match receive_message(&channel_name, timeout_ms) {
Ok(data) => {
let len = std::cmp::min(data.len(), max_len as usize);
unsafe {
std::ptr::copy_nonoverlapping(data.as_ptr(), buf as *mut u8, len);
}
len as c_int
}
Err(_) => -1,
}
}
-167
View File
@@ -1,167 +0,0 @@
use axum::{
routing::{get, post},
Router,
Json,
extract::State,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info, error};
mod analytics;
mod reports;
mod ipc;
use analytics::AnalyticsEngine;
use reports::ReportGenerator;
#[derive(Clone)]
struct AppState {
analytics: Arc<RwLock<AnalyticsEngine>>,
reports: Arc<RwLock<ReportGenerator>>,
}
#[derive(Serialize)]
struct HealthResponse {
status: String,
service: String,
version: String,
}
#[derive(Deserialize)]
struct ReportRequest {
tenant_id: String,
report_type: String,
parameters: serde_json::Value,
}
#[derive(Serialize)]
struct ReportResponse {
report_id: String,
status: String,
data: Option<serde_json::Value>,
}
#[derive(Deserialize)]
struct AnalyticsRequest {
tenant_id: String,
metric: String,
period: String,
}
#[derive(Serialize)]
struct AnalyticsResponse {
metric: String,
value: f64,
trend: f64,
breakdown: Vec<BreakdownItem>,
}
#[derive(Serialize)]
struct BreakdownItem {
label: String,
value: f64,
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_env_filter("boc_rust_service=info")
.init();
info!("BOC Rust Service starting...");
let state = AppState {
analytics: Arc::new(RwLock::new(AnalyticsEngine::new())),
reports: Arc::new(RwLock::new(ReportGenerator::new())),
};
let app = Router::new()
.route("/health", get(health_handler))
.route("/api/v1/reports/generate", post(generate_report))
.route("/api/v1/analytics/query", post(query_analytics))
.route("/api/v1/analytics/batch", post(batch_analytics))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:9093")
.await
.expect("Failed to bind port 9093");
info!("BOC Rust Service listening on 0.0.0.0:9093");
axum::serve(listener, app)
.await
.expect("Server failed");
}
async fn health_handler() -> Json<HealthResponse> {
Json(HealthResponse {
status: "ok".to_string(),
service: "boc-rust-service".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
})
}
async fn generate_report(
State(state): State<AppState>,
Json(req): Json<ReportRequest>,
) -> Json<ReportResponse> {
info!("Generating report: {} for tenant: {}", req.report_type, req.tenant_id);
let reports = state.reports.read().await;
match reports.generate(&req.tenant_id, &req.report_type, &req.parameters).await {
Ok(data) => Json(ReportResponse {
report_id: uuid::Uuid::new_v4().to_string(),
status: "completed".to_string(),
data: Some(data),
}),
Err(e) => {
error!("Report generation failed: {}", e);
Json(ReportResponse {
report_id: uuid::Uuid::new_v4().to_string(),
status: "failed".to_string(),
data: None,
})
}
}
}
async fn query_analytics(
State(state): State<AppState>,
Json(req): Json<AnalyticsRequest>,
) -> Json<AnalyticsResponse> {
let analytics = state.analytics.read().await;
let result = analytics.query(&req.tenant_id, &req.metric, &req.period).await;
Json(AnalyticsResponse {
metric: req.metric,
value: result.value,
trend: result.trend,
breakdown: result.breakdown.into_iter()
.map(|(label, value)| BreakdownItem { label, value })
.collect(),
})
}
async fn batch_analytics(
State(state): State<AppState>,
Json(reqs): Json<Vec<AnalyticsRequest>>,
) -> Json<Vec<AnalyticsResponse>> {
let analytics = state.analytics.read().await;
let mut responses = Vec::with_capacity(reqs.len());
for req in reqs {
let result = analytics.query(&req.tenant_id, &req.metric, &req.period).await;
responses.push(AnalyticsResponse {
metric: req.metric.clone(),
value: result.value,
trend: result.trend,
breakdown: result.breakdown.into_iter()
.map(|(label, value)| BreakdownItem { label, value })
.collect(),
});
}
Json(responses)
}
-167
View File
@@ -1,167 +0,0 @@
use axum::{
routing::{get, post},
Router,
Json,
extract::State,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info, error};
mod analytics;
mod reports;
mod ipc;
use analytics::AnalyticsEngine;
use reports::ReportGenerator;
#[derive(Clone)]
struct AppState {
analytics: Arc<RwLock<AnalyticsEngine>>,
reports: Arc<RwLock<ReportGenerator>>,
}
#[derive(Serialize)]
struct HealthResponse {
status: String,
service: String,
version: String,
}
#[derive(Deserialize)]
struct ReportRequest {
tenant_id: String,
report_type: String,
parameters: serde_json::Value,
}
#[derive(Serialize)]
struct ReportResponse {
report_id: String,
status: String,
data: Option<serde_json::Value>,
}
#[derive(Deserialize)]
struct AnalyticsRequest {
tenant_id: String,
metric: String,
period: String,
}
#[derive(Serialize)]
struct AnalyticsResponse {
metric: String,
value: f64,
trend: f64,
breakdown: Vec<BreakdownItem>,
}
#[derive(Serialize)]
struct BreakdownItem {
label: String,
value: f64,
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_env_filter("boc_rust_service=info")
.init();
info!("BOC Rust Service starting...");
let state = AppState {
analytics: Arc::new(RwLock::new(AnalyticsEngine::new())),
reports: Arc::new(RwLock::new(ReportGenerator::new())),
};
let app = Router::new()
.route("/health", get(health_handler))
.route("/api/v1/reports/generate", post(generate_report))
.route("/api/v1/analytics/query", post(query_analytics))
.route("/api/v1/analytics/batch", post(batch_analytics))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:9093")
.await
.expect("Failed to bind port 9093");
info!("BOC Rust Service listening on 0.0.0.0:9093");
axum::serve(listener, app)
.await
.expect("Server failed");
}
async fn health_handler() -> Json<HealthResponse> {
Json(HealthResponse {
status: "ok".to_string(),
service: "boc-rust-service".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
})
}
async fn generate_report(
State(state): State<AppState>,
Json(req): Json<ReportRequest>,
) -> Json<ReportResponse> {
info!("Generating report: {} for tenant: {}", req.report_type, req.tenant_id);
let reports = state.reports.read().await;
match reports.generate(&req.tenant_id, &req.report_type, &req.parameters).await {
Ok(data) => Json(ReportResponse {
report_id: uuid::Uuid::new_v4().to_string(),
status: "completed".to_string(),
data: Some(data),
}),
Err(e) => {
error!("Report generation failed: {}", e);
Json(ReportResponse {
report_id: uuid::Uuid::new_v4().to_string(),
status: "failed".to_string(),
data: None,
})
}
}
}
async fn query_analytics(
State(state): State<AppState>,
Json(req): Json<AnalyticsRequest>,
) -> Json<AnalyticsResponse> {
let analytics = state.analytics.read().await;
let result = analytics.query(&req.tenant_id, &req.metric, &req.period).await;
Json(AnalyticsResponse {
metric: req.metric,
value: result.value,
trend: result.trend,
breakdown: result.breakdown.into_iter()
.map(|(label, value)| BreakdownItem { label, value })
.collect(),
})
}
async fn batch_analytics(
State(state): State<AppState>,
Json(reqs): Json<Vec<AnalyticsRequest>>,
) -> Json<Vec<AnalyticsResponse>> {
let analytics = state.analytics.read().await;
let mut responses = Vec::with_capacity(reqs.len());
for req in reqs {
let result = analytics.query(&req.tenant_id, &req.metric, &req.period).await;
responses.push(AnalyticsResponse {
metric: req.metric.clone(),
value: result.value,
trend: result.trend,
breakdown: result.breakdown.into_iter()
.map(|(label, value)| BreakdownItem { label, value })
.collect(),
});
}
Json(responses)
}
-261
View File
@@ -1,261 +0,0 @@
use chrono::{DateTime, Utc};
use serde_json::{json, Value};
use std::collections::HashMap;
pub struct ReportGenerator {
templates: HashMap<String, ReportTemplate>,
}
struct ReportTemplate {
name: String,
description: String,
required_params: Vec<String>,
}
impl ReportGenerator {
pub fn new() -> Self {
let mut templates = HashMap::new();
templates.insert("financial_summary".to_string(), ReportTemplate {
name: "Financial Summary".to_string(),
description: "Overview of financial performance".to_string(),
required_params: vec!["period".to_string()],
});
templates.insert("sales_pipeline".to_string(), ReportTemplate {
name: "Sales Pipeline".to_string(),
description: "Current sales pipeline analysis".to_string(),
required_params: vec!["period".to_string()],
});
templates.insert("customer_analytics".to_string(), ReportTemplate {
name: "Customer Analytics".to_string(),
description: "Customer metrics and trends".to_string(),
required_params: vec!["period".to_string()],
});
templates.insert("revenue_forecast".to_string(), ReportTemplate {
name: "Revenue Forecast".to_string(),
description: "Projected revenue based on pipeline".to_string(),
required_params: vec!["period".to_string(), "method".to_string()],
});
templates.insert("expense_breakdown".to_string(), ReportTemplate {
name: "Expense Breakdown".to_string(),
description: "Detailed expense analysis".to_string(),
required_params: vec!["period".to_string()],
});
templates.insert("cashflow_projection".to_string(), ReportTemplate {
name: "Cashflow Projection".to_string(),
description: "Projected cashflow for upcoming periods".to_string(),
required_params: vec!["periods".to_string()],
});
Self { templates }
}
pub async fn generate(
&self,
tenant_id: &str,
report_type: &str,
parameters: &Value,
) -> Result<Value, String> {
let template = self.templates.get(report_type)
.ok_or_else(|| format!("Unknown report type: {}", report_type))?;
// Validate required parameters
for param in &template.required_params {
if parameters.get(param).is_none() {
return Err(format!("Missing required parameter: {}", param));
}
}
match report_type {
"financial_summary" => self.generate_financial_summary(tenant_id, parameters).await,
"sales_pipeline" => self.generate_sales_pipeline(tenant_id, parameters).await,
"customer_analytics" => self.generate_customer_analytics(tenant_id, parameters).await,
"revenue_forecast" => self.generate_revenue_forecast(tenant_id, parameters).await,
"expense_breakdown" => self.generate_expense_breakdown(tenant_id, parameters).await,
"cashflow_projection" => self.generate_cashflow_projection(tenant_id, parameters).await,
_ => Err(format!("Report type not implemented: {}", report_type)),
}
}
async fn generate_financial_summary(&self, tenant_id: &str, params: &Value) -> Result<Value, String> {
let period = params.get("period").and_then(|v| v.as_str()).unwrap_or("current_month");
Ok(json!({
"report_type": "financial_summary",
"period": period,
"generated_at": Utc::now().to_rfc3339(),
"summary": {
"total_revenue": 125000.00,
"total_expenses": 87500.00,
"net_income": 37500.00,
"profit_margin": 0.30,
"mrr": 53333.00,
"arr": 640000.00,
"cash_on_hand": 180000.00,
"burn_rate": 45000.00,
"runway_months": 4.0
},
"revenue_breakdown": [
{"category": "Subscriptions", "amount": 95000.00, "percentage": 0.76},
{"category": "Services", "amount": 20000.00, "percentage": 0.16},
{"category": "Other", "amount": 10000.00, "percentage": 0.08}
],
"expense_breakdown": [
{"category": "Personnel", "amount": 50000.00, "percentage": 0.57},
{"category": "Infrastructure", "amount": 15000.00, "percentage": 0.17},
{"category": "Marketing", "amount": 12500.00, "percentage": 0.14},
{"category": "Other", "amount": 10000.00, "percentage": 0.12}
]
}))
}
async fn generate_sales_pipeline(&self, tenant_id: &str, params: &Value) -> Result<Value, String> {
let period = params.get("period").and_then(|v| v.as_str()).unwrap_or("current");
Ok(json!({
"report_type": "sales_pipeline",
"period": period,
"generated_at": Utc::now().to_rfc3339(),
"pipeline": {
"total_value": 850000.00,
"total_deals": 24,
"weighted_value": 425000.00,
"avg_deal_size": 35417.00,
"avg_sales_cycle_days": 45
},
"by_stage": [
{"stage": "Prospect", "count": 8, "value": 200000.00, "probability": 0.10},
{"stage": "Qualified", "count": 6, "value": 300000.00, "probability": 0.30},
{"stage": "Proposal", "count": 5, "value": 250000.00, "probability": 0.60},
{"stage": "Negotiation", "count": 3, "value": 100000.00, "probability": 0.80},
{"stage": "Closed Won", "count": 2, "value": 75000.00, "probability": 1.00}
],
"trends": {
"new_deals_this_month": 5,
"deals_moved_forward": 3,
"deals_stalled": 2,
"deals_lost": 1,
"win_rate": 0.67
}
}))
}
async fn generate_customer_analytics(&self, tenant_id: &str, params: &Value) -> Result<Value, String> {
let period = params.get("period").and_then(|v| v.as_str()).unwrap_or("current_month");
Ok(json!({
"report_type": "customer_analytics",
"period": period,
"generated_at": Utc::now().to_rfc3339(),
"overview": {
"total_customers": 42,
"new_customers": 5,
"churned_customers": 1,
"active_customers": 38,
"net_revenue_retention": 1.08,
"gross_revenue_retention": 0.95
},
"segments": [
{"segment": "Enterprise", "count": 3, "mrr": 25000.00, "ltv": 250000.00},
{"segment": "Professional", "count": 12, "mrr": 18000.00, "ltv": 100000.00},
{"segment": "Basic", "count": 27, "mrr": 10333.00, "ltv": 25000.00}
],
"health": {
"at_risk": 2,
"expanding": 5,
"stable": 31,
"new": 5
}
}))
}
async fn generate_revenue_forecast(&self, tenant_id: &str, params: &Value) -> Result<Value, String> {
let period = params.get("period").and_then(|v| v.as_str()).unwrap_or("next_quarter");
let method = params.get("method").and_then(|v| v.as_str()).unwrap_or("weighted_pipeline");
Ok(json!({
"report_type": "revenue_forecast",
"period": period,
"method": method,
"generated_at": Utc::now().to_rfc3339(),
"forecast": {
"conservative": 180000.00,
"expected": 250000.00,
"optimistic": 350000.00
},
"monthly_breakdown": [
{"month": "Month 1", "conservative": 55000.00, "expected": 75000.00, "optimistic": 100000.00},
{"month": "Month 2", "conservative": 60000.00, "expected": 85000.00, "optimistic": 120000.00},
{"month": "Month 3", "conservative": 65000.00, "expected": 90000.00, "optimistic": 130000.00}
],
"assumptions": [
"Current pipeline velocity maintained",
"No significant churn increase",
"Marketing spend constant"
]
}))
}
async fn generate_expense_breakdown(&self, tenant_id: &str, params: &Value) -> Result<Value, String> {
let period = params.get("period").and_then(|v| v.as_str()).unwrap_or("current_month");
Ok(json!({
"report_type": "expense_breakdown",
"period": period,
"generated_at": Utc::now().to_rfc3339(),
"total_expenses": 87500.00,
"by_category": [
{"category": "Personnel", "amount": 50000.00, "percentage": 0.57, "trend": 0.02},
{"category": "Infrastructure", "amount": 15000.00, "percentage": 0.17, "trend": -0.05},
{"category": "Marketing", "amount": 12500.00, "percentage": 0.14, "trend": 0.10},
{"category": "Software", "amount": 6000.00, "percentage": 0.07, "trend": 0.0},
{"category": "Other", "amount": 4000.00, "percentage": 0.05, "trend": -0.02}
],
"recurring_vs_one_time": {
"recurring": 75000.00,
"one_time": 12500.00
}
}))
}
async fn generate_cashflow_projection(&self, tenant_id: &str, params: &Value) -> Result<Value, String> {
let periods = params.get("periods").and_then(|v| v.as_i64()).unwrap_or(6);
let mut projections = Vec::new();
let mut current_cash = 180000.00;
for i in 1..=periods {
let inflow = 120000.00 + (i as f64 * 5000.00);
let outflow = 87500.00 + (i as f64 * 2000.00);
let net = inflow - outflow;
current_cash += net;
projections.push(json!({
"period": format!("Month {}", i),
"inflow": inflow,
"outflow": outflow,
"net": net,
"ending_cash": current_cash
}));
}
Ok(json!({
"report_type": "cashflow_projection",
"periods": periods,
"generated_at": Utc::now().to_rfc3339(),
"starting_cash": 180000.00,
"projections": projections,
"summary": {
"total_inflow": projections.iter().map(|p| p.get("inflow").unwrap().as_f64().unwrap()).sum::<f64>(),
"total_outflow": projections.iter().map(|p| p.get("outflow").unwrap().as_f64().unwrap()).sum::<f64>(),
"ending_cash": current_cash,
"min_cash": projections.iter().map(|p| p.get("ending_cash").unwrap().as_f64().unwrap()).fold(f64::INFINITY, f64::min)
}
}))
}
}