bijux-dag-runtime 0.4.1

Execution engine, replay semantics, and runtime policy layer for Bijux DAG graphs.
Documentation
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SyntheticDagProfile {
    pub name: String,
    pub depth: usize,
    pub fan_out: usize,
    pub branch_factor: usize,
    pub partitions: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BenchmarkResult {
    pub name: String,
    pub throughput_per_sec: f64,
    pub p95_latency_ms: f64,
    pub memory_mb: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SchedulerScalabilityResult {
    pub queue_throughput_per_sec: f64,
    pub fairness_score: f64,
    pub admission_latency_ms: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ArtifactStoreBenchmarkResult {
    pub read_mbps: f64,
    pub write_mbps: f64,
    pub dedup_ratio: f64,
    pub gc_minutes: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapacityModel {
    pub scheduler_capacity: usize,
    pub worker_capacity: usize,
    pub artifact_iops: usize,
    pub registry_qps: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AutoscalingHint {
    pub target_component: String,
    pub current_replicas: usize,
    pub recommended_replicas: usize,
    pub reason: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StorageGrowthForecast {
    pub daily_gb: f64,
    pub monthly_gb: f64,
    pub annual_gb: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StorageCostModel {
    pub local_store_monthly_cost: f64,
    pub object_store_monthly_cost: f64,
    pub hot_cache_monthly_cost: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PerformanceGate {
    pub family: String,
    pub max_latency_regression_pct: u32,
    pub min_throughput_retention_pct: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct EnvironmentScaleProfile {
    pub environment: String,
    pub max_active_runs: usize,
    pub max_parallel_nodes: usize,
    pub expected_artifact_gb_per_day: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PerformanceMaturityReport {
    pub throughput_trend: f64,
    pub latency_trend: f64,
    pub utilization_trend: f64,
    pub cost_trend: f64,
}

pub fn synthetic_large_dag_profiles() -> Vec<SyntheticDagProfile> {
    vec![
        SyntheticDagProfile {
            name: "deep-chain".to_string(),
            depth: 1000,
            fan_out: 1,
            branch_factor: 1,
            partitions: 1,
        },
        SyntheticDagProfile {
            name: "wide-fanout".to_string(),
            depth: 20,
            fan_out: 200,
            branch_factor: 3,
            partitions: 8,
        },
        SyntheticDagProfile {
            name: "mixed-partition-branch".to_string(),
            depth: 120,
            fan_out: 20,
            branch_factor: 5,
            partitions: 64,
        },
    ]
}

pub fn derive_autoscaling_hint(
    queue_depth: usize,
    dispatch_lag_seconds: u32,
    saturation_pct: u32,
    current_replicas: usize,
) -> AutoscalingHint {
    let mut recommended = current_replicas;
    if queue_depth > 1000 || dispatch_lag_seconds > 30 || saturation_pct > 80 {
        recommended += 2;
    }
    AutoscalingHint {
        target_component: "scheduler-workers".to_string(),
        current_replicas,
        recommended_replicas: recommended,
        reason: format!(
            "queue_depth={queue_depth}, dispatch_lag_seconds={dispatch_lag_seconds}, saturation_pct={saturation_pct}"
        ),
    }
}

pub fn forecast_storage_growth(daily_gb: f64) -> StorageGrowthForecast {
    StorageGrowthForecast { daily_gb, monthly_gb: daily_gb * 30.0, annual_gb: daily_gb * 365.0 }
}

pub fn build_cost_model(
    local_gb: f64,
    object_gb: f64,
    cache_gb: f64,
    local_cost_per_gb: f64,
    object_cost_per_gb: f64,
    cache_cost_per_gb: f64,
) -> StorageCostModel {
    StorageCostModel {
        local_store_monthly_cost: local_gb * local_cost_per_gb,
        object_store_monthly_cost: object_gb * object_cost_per_gb,
        hot_cache_monthly_cost: cache_gb * cache_cost_per_gb,
    }
}

pub fn detect_performance_regression(
    baseline: &BenchmarkResult,
    candidate: &BenchmarkResult,
    gate: &PerformanceGate,
) -> Vec<String> {
    let mut violations = Vec::new();
    let latency_regression =
        ((candidate.p95_latency_ms - baseline.p95_latency_ms) / baseline.p95_latency_ms) * 100.0;
    let throughput_retention = (candidate.throughput_per_sec / baseline.throughput_per_sec) * 100.0;

    if latency_regression > gate.max_latency_regression_pct as f64 {
        violations.push(format!(
            "latency regression {:.2}% exceeds {}%",
            latency_regression, gate.max_latency_regression_pct
        ));
    }
    if throughput_retention < gate.min_throughput_retention_pct as f64 {
        violations.push(format!(
            "throughput retention {:.2}% below {}%",
            throughput_retention, gate.min_throughput_retention_pct
        ));
    }
    violations
}

pub fn compile_environment_profiles() -> BTreeMap<String, EnvironmentScaleProfile> {
    BTreeMap::from([
        (
            "dev".to_string(),
            EnvironmentScaleProfile {
                environment: "dev".to_string(),
                max_active_runs: 20,
                max_parallel_nodes: 100,
                expected_artifact_gb_per_day: 5,
            },
        ),
        (
            "ci".to_string(),
            EnvironmentScaleProfile {
                environment: "ci".to_string(),
                max_active_runs: 100,
                max_parallel_nodes: 500,
                expected_artifact_gb_per_day: 30,
            },
        ),
        (
            "staging".to_string(),
            EnvironmentScaleProfile {
                environment: "staging".to_string(),
                max_active_runs: 500,
                max_parallel_nodes: 2_000,
                expected_artifact_gb_per_day: 120,
            },
        ),
        (
            "prod".to_string(),
            EnvironmentScaleProfile {
                environment: "prod".to_string(),
                max_active_runs: 5_000,
                max_parallel_nodes: 20_000,
                expected_artifact_gb_per_day: 2_000,
            },
        ),
    ])
}

pub fn build_performance_maturity_report(
    throughput_trend: f64,
    latency_trend: f64,
    utilization_trend: f64,
    cost_trend: f64,
) -> PerformanceMaturityReport {
    PerformanceMaturityReport { throughput_trend, latency_trend, utilization_trend, cost_trend }
}