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 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-02-26 17:38:43 +01:00
parent 4a202207d3
commit 265bd2441c
16 changed files with 97 additions and 7 deletions

View File

@@ -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]

View File

@@ -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

View File

@@ -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};

View File

@@ -160,6 +160,15 @@ impl Denoiser {
vb: VarBuilder<'_>,
device: &Device,
) -> Result<Self, MLError> {
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"))

View File

@@ -811,6 +811,17 @@ pub struct DQN {
impl DQN {
/// Create new `DQN`
pub fn new(config: DQNConfig) -> Result<Self, MLError> {
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

View File

@@ -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 {

View File

@@ -244,6 +244,17 @@ pub struct CandleCfCNetwork {
impl CandleCfCNetwork {
pub fn new(config: &CfCTrainConfig, vb: &VarBuilder<'_>) -> Result<Self, MLError> {
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"))

View File

@@ -620,6 +620,12 @@ impl Mamba2SSM {
/// - Layer norm creation fails
/// - SSD layer initialization fails
pub fn new(config: Mamba2Config, device: &Device) -> Result<Self, MLError> {
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);

View File

@@ -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<Self, MLError> {
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;

View File

@@ -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!(

View File

@@ -72,6 +72,17 @@ impl TGGNTrainableAdapter {
/// # Returns
/// Initialized adapter ready for training
pub fn new(config: TGGNConfig, device: &Device) -> Result<Self, MLError> {
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);

View File

@@ -103,6 +103,15 @@ impl TLOBTrainableAdapter {
/// # Returns
/// Initialized adapter ready for training
pub fn new(config: TLOBAdapterConfig, device: &Device) -> Result<Self, MLError> {
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);

View File

@@ -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;

View File

@@ -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") };
}

View File

@@ -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);
}
}

View File

@@ -1349,6 +1349,7 @@ impl ConfigRepository for PostgresConfigRepository {
// =============================================================================
#[cfg(test)]
#[allow(dead_code)]
mod mock_repositories {
use super::*;