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:
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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") };
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1349,6 +1349,7 @@ impl ConfigRepository for PostgresConfigRepository {
|
||||
// =============================================================================
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
mod mock_repositories {
|
||||
use super::*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user