From 265bd2441c5d536c4cae90bb70bc9f28fa96e6f2 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Thu, 26 Feb 2026 17:38:43 +0100 Subject: [PATCH] fix(ml,ci): zero-dim guards on all 10 models, eliminate warnings, unblock CI parallelism - Add dimension validation in DQN, PPO, Mamba2, TGGN, TLOB, Liquid, KAN, xLSTM, Diffusion constructors (fail-fast on zero-dim inputs that would cause CUDA_ERROR_INVALID_VALUE at runtime) - Add num_unknown_features > 0 guard to TFT (temporal input required) - Fix 12 dead-code/unused warnings in test compilation - Remove opt-level=3 and codegen-units=1 from target rustflags (was forcing O3 + single-thread codegen on dev/test builds) - Remove hardcoded jobs=16 cap (cargo now auto-detects CPU count) - Switch linker to clang+lld (2-5x faster linking) Co-Authored-By: Claude Opus 4.6 --- .cargo/config.toml | 11 +++++++---- crates/common/src/metrics/tests/registry_test.rs | 1 - crates/ml/examples/baseline_common/mod.rs | 1 + crates/ml/src/diffusion/denoiser.rs | 9 +++++++++ crates/ml/src/dqn/dqn.rs | 11 +++++++++++ crates/ml/src/kan/network.rs | 5 +++++ crates/ml/src/liquid/candle_cfc.rs | 11 +++++++++++ crates/ml/src/mamba/mod.rs | 6 ++++++ crates/ml/src/ppo/ppo.rs | 11 +++++++++++ crates/ml/src/tft/mod.rs | 5 +++++ crates/ml/src/tgnn/trainable_adapter.rs | 11 +++++++++++ crates/ml/src/tlob/trainable_adapter.rs | 9 +++++++++ crates/ml/src/xlstm/network.rs | 8 ++++++++ crates/web-gateway/src/routes/auth.rs | 2 ++ services/trading_service/src/ensemble_risk_manager.rs | 2 -- services/trading_service/src/repository_impls.rs | 1 + 16 files changed, 97 insertions(+), 7 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index ae3125540..8a58a6859 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -8,7 +8,7 @@ vcs = "none" git-fetch-with-cli = true [build] -jobs = 16 +# jobs: omitted → cargo uses all logical CPUs (scales to any machine) incremental = true pipelining = true rustflags = [ @@ -24,14 +24,17 @@ verbose = false progress.when = "auto" [target.x86_64-unknown-linux-gnu] +linker = "clang" rustflags = [ + "-C", "link-arg=-fuse-ld=lld", "-C", "link-arg=-Wl,-z,relro,-z,now", "-C", "link-arg=-Wl,--as-needed", - # RUNPOD COMPATIBILITY: x86-64-v3 (AVX2/FMA) NOT native (NO AVX-512) + # AVX2/FMA baseline — matches both Scaleway L4/H100 and most dev machines "-C", "target-cpu=x86-64-v3", "-C", "target-feature=+avx2,+fma,+bmi2", - "-C", "opt-level=3", - "-C", "codegen-units=1", + # opt-level and codegen-units are set per-profile, NOT here. + # Setting them here would override ALL profiles (dev/test included), + # forcing full O3 + single-thread codegen on test builds. ] [profile.release] diff --git a/crates/common/src/metrics/tests/registry_test.rs b/crates/common/src/metrics/tests/registry_test.rs index 07cece4d4..95e54da29 100644 --- a/crates/common/src/metrics/tests/registry_test.rs +++ b/crates/common/src/metrics/tests/registry_test.rs @@ -148,7 +148,6 @@ mod tests { #[test] fn test_concurrent_metric_updates() { - use std::sync::Arc; use std::thread; // Register a counter for concurrent access diff --git a/crates/ml/examples/baseline_common/mod.rs b/crates/ml/examples/baseline_common/mod.rs index baa07c975..475d30d66 100644 --- a/crates/ml/examples/baseline_common/mod.rs +++ b/crates/ml/examples/baseline_common/mod.rs @@ -4,6 +4,7 @@ //! and cost helpers used by `train_baseline`, `evaluate_baseline`, and //! `hyperopt_baseline`. +#[allow(dead_code)] pub mod completion; use std::path::{Path, PathBuf}; diff --git a/crates/ml/src/diffusion/denoiser.rs b/crates/ml/src/diffusion/denoiser.rs index 3a7f66a5d..034d45120 100644 --- a/crates/ml/src/diffusion/denoiser.rs +++ b/crates/ml/src/diffusion/denoiser.rs @@ -160,6 +160,15 @@ impl Denoiser { vb: VarBuilder<'_>, device: &Device, ) -> Result { + if data_dim == 0 || hidden_dim == 0 { + return Err(MLError::ConfigError { + reason: format!( + "Diffusion denoiser requires data_dim > 0 and hidden_dim > 0 (got {}x{})", + data_dim, hidden_dim + ), + }); + } + let time_embed = TimeEmbedding::new(time_embed_dim, hidden_dim, vb.pp("time_embed"))?; let input_proj = linear(data_dim, hidden_dim, vb.pp("input_proj")) diff --git a/crates/ml/src/dqn/dqn.rs b/crates/ml/src/dqn/dqn.rs index 204619175..015fa2ad3 100644 --- a/crates/ml/src/dqn/dqn.rs +++ b/crates/ml/src/dqn/dqn.rs @@ -811,6 +811,17 @@ pub struct DQN { impl DQN { /// Create new `DQN` pub fn new(config: DQNConfig) -> Result { + if config.state_dim == 0 { + return Err(MLError::ConfigError { + reason: "DQN requires state_dim > 0".to_owned(), + }); + } + if config.num_actions == 0 { + return Err(MLError::ConfigError { + reason: "DQN requires num_actions > 0".to_owned(), + }); + } + let device = Device::cuda_if_available(0)?; // Use GPU if available, fallback to CPU // Create main Q-network diff --git a/crates/ml/src/kan/network.rs b/crates/ml/src/kan/network.rs index e6dc24245..fd0d21d0d 100644 --- a/crates/ml/src/kan/network.rs +++ b/crates/ml/src/kan/network.rs @@ -29,6 +29,11 @@ impl KANNetwork { reason: "layer_widths must have at least 2 entries".to_owned(), }); } + if config.layer_widths.iter().any(|&w| w == 0) { + return Err(MLError::ConfigError { + reason: "KAN requires all layer_widths > 0".to_owned(), + }); + } let mut layers = Vec::with_capacity(config.layer_widths.len() - 1); for i in 0..config.layer_widths.len() - 1 { diff --git a/crates/ml/src/liquid/candle_cfc.rs b/crates/ml/src/liquid/candle_cfc.rs index 39ec023da..4ae09f60a 100644 --- a/crates/ml/src/liquid/candle_cfc.rs +++ b/crates/ml/src/liquid/candle_cfc.rs @@ -244,6 +244,17 @@ pub struct CandleCfCNetwork { impl CandleCfCNetwork { pub fn new(config: &CfCTrainConfig, vb: &VarBuilder<'_>) -> Result { + if config.input_size == 0 { + return Err(MLError::ConfigError { + reason: "Liquid CfC requires input_size > 0".to_owned(), + }); + } + if config.hidden_size == 0 { + return Err(MLError::ConfigError { + reason: "Liquid CfC requires hidden_size > 0".to_owned(), + }); + } + let cell = CfCCell::new(config, &vb.pp("cfc"))?; let output_layer = candle_nn::linear(config.hidden_size, config.output_size, vb.pp("output")) diff --git a/crates/ml/src/mamba/mod.rs b/crates/ml/src/mamba/mod.rs index 1a10ab9ef..53646ba3c 100644 --- a/crates/ml/src/mamba/mod.rs +++ b/crates/ml/src/mamba/mod.rs @@ -620,6 +620,12 @@ impl Mamba2SSM { /// - Layer norm creation fails /// - SSD layer initialization fails pub fn new(config: Mamba2Config, device: &Device) -> Result { + if config.d_model == 0 { + return Err(MLError::ConfigError { + reason: "Mamba2 requires d_model > 0".to_owned(), + }); + } + let vs = Arc::new(candle_nn::VarMap::new()); let vb = VarBuilder::from_varmap(&vs, DType::F64, device); diff --git a/crates/ml/src/ppo/ppo.rs b/crates/ml/src/ppo/ppo.rs index 9f0c3406f..b9a5d57cb 100644 --- a/crates/ml/src/ppo/ppo.rs +++ b/crates/ml/src/ppo/ppo.rs @@ -723,6 +723,17 @@ impl PPO { /// 3. Training uses `TrajectoryBatch::to_sequences()` for BPTT /// 4. `HiddenStateManager` is initialized automatically pub fn with_device(config: PPOConfig, device: Device) -> Result { + if config.state_dim == 0 { + return Err(MLError::ConfigError { + reason: "PPO requires state_dim > 0".to_owned(), + }); + } + if config.num_actions == 0 { + return Err(MLError::ConfigError { + reason: "PPO requires num_actions > 0".to_owned(), + }); + } + // Extract values before moving config let use_lstm = config.use_lstm; let lstm_hidden_dim = config.lstm_hidden_dim; diff --git a/crates/ml/src/tft/mod.rs b/crates/ml/src/tft/mod.rs index 52c359c3f..2d28c176d 100644 --- a/crates/ml/src/tft/mod.rs +++ b/crates/ml/src/tft/mod.rs @@ -308,6 +308,11 @@ impl TemporalFusionTransformer { // Validate configuration let total_features = config.num_static_features + config.num_known_features + config.num_unknown_features; + if config.num_unknown_features == 0 { + return Err(MLError::ConfigError { + reason: "TFT requires num_unknown_features > 0 (temporal input)".to_owned(), + }); + } if total_features != config.input_dim { return Err(MLError::ConfigError { reason: format!( diff --git a/crates/ml/src/tgnn/trainable_adapter.rs b/crates/ml/src/tgnn/trainable_adapter.rs index 46bd41161..acfa99efd 100644 --- a/crates/ml/src/tgnn/trainable_adapter.rs +++ b/crates/ml/src/tgnn/trainable_adapter.rs @@ -72,6 +72,17 @@ impl TGGNTrainableAdapter { /// # Returns /// Initialized adapter ready for training pub fn new(config: TGGNConfig, device: &Device) -> Result { + if config.node_dim == 0 { + return Err(MLError::ConfigError { + reason: "TGGN requires node_dim > 0".to_owned(), + }); + } + if config.hidden_dim == 0 { + return Err(MLError::ConfigError { + reason: "TGGN requires hidden_dim > 0".to_owned(), + }); + } + let var_map = VarMap::new(); let vb = VarBuilder::from_varmap(&var_map, DType::F32, device); diff --git a/crates/ml/src/tlob/trainable_adapter.rs b/crates/ml/src/tlob/trainable_adapter.rs index b2b0acfb1..b450604be 100644 --- a/crates/ml/src/tlob/trainable_adapter.rs +++ b/crates/ml/src/tlob/trainable_adapter.rs @@ -103,6 +103,15 @@ impl TLOBTrainableAdapter { /// # Returns /// Initialized adapter ready for training pub fn new(config: TLOBAdapterConfig, device: &Device) -> Result { + if config.seq_len == 0 || config.feature_dim == 0 { + return Err(MLError::ConfigError { + reason: format!( + "TLOB requires seq_len > 0 and feature_dim > 0 (got {}x{})", + config.seq_len, config.feature_dim + ), + }); + } + let var_map = VarMap::new(); let vb = VarBuilder::from_varmap(&var_map, DType::F32, device); diff --git a/crates/ml/src/xlstm/network.rs b/crates/ml/src/xlstm/network.rs index ffbd942f2..118c1f78f 100644 --- a/crates/ml/src/xlstm/network.rs +++ b/crates/ml/src/xlstm/network.rs @@ -32,6 +32,14 @@ impl XLSTMNetwork { reason: "num_blocks must be >= 1".to_owned(), }); } + if config.input_dim == 0 || config.hidden_dim == 0 { + return Err(MLError::ConfigError { + reason: format!( + "xLSTM requires input_dim > 0 and hidden_dim > 0 (got {}x{})", + config.input_dim, config.hidden_dim + ), + }); + } let num_slstm = ((config.num_blocks as f64) * config.slstm_ratio).round() as usize; diff --git a/crates/web-gateway/src/routes/auth.rs b/crates/web-gateway/src/routes/auth.rs index dd5fd8488..b28bf8ccf 100644 --- a/crates/web-gateway/src/routes/auth.rs +++ b/crates/web-gateway/src/routes/auth.rs @@ -102,7 +102,9 @@ mod tests { } /// Enable the dev auth stub for tests that need it + #[allow(unsafe_code)] fn enable_dev_auth() { + // SAFETY: test-only; each test runs serially (no concurrent env reads). unsafe { std::env::set_var("FOXHUNT_DEV_AUTH", "true") }; } diff --git a/services/trading_service/src/ensemble_risk_manager.rs b/services/trading_service/src/ensemble_risk_manager.rs index 66dc7bfc7..ad13f1e5d 100644 --- a/services/trading_service/src/ensemble_risk_manager.rs +++ b/services/trading_service/src/ensemble_risk_manager.rs @@ -710,7 +710,5 @@ mod tests { assert!(result.approved); assert!(result.rejection_reason.is_none()); - // Allow fast test environments (can complete in <1μs) - assert!(result.validation_latency_us >= 0); } } diff --git a/services/trading_service/src/repository_impls.rs b/services/trading_service/src/repository_impls.rs index f06d5ad43..b89c95097 100644 --- a/services/trading_service/src/repository_impls.rs +++ b/services/trading_service/src/repository_impls.rs @@ -1349,6 +1349,7 @@ impl ConfigRepository for PostgresConfigRepository { // ============================================================================= #[cfg(test)] +#[allow(dead_code)] mod mock_repositories { use super::*;