diff --git a/crates/ml/src/trainers/dqn/trainer/constructor.rs b/crates/ml/src/trainers/dqn/trainer/constructor.rs index 540bb3eb4..e22681523 100644 --- a/crates/ml/src/trainers/dqn/trainer/constructor.rs +++ b/crates/ml/src/trainers/dqn/trainer/constructor.rs @@ -30,6 +30,13 @@ use super::DQNTrainer; impl DQNTrainer { pub(crate) fn new_internal(mut hyperparams: DQNHyperparameters, debug_logging: bool, override_device: Option) -> Result { + // Validate batch_size > 0 + if hyperparams.batch_size == 0 { + return Err(anyhow::anyhow!( + "batch_size must be greater than 0" + )); + } + // WAVE 26 P2.2: Validate gradient_accumulation_steps > 0 if hyperparams.gradient_accumulation_steps == 0 { return Err(anyhow::anyhow!( diff --git a/crates/ml/src/trainers/dqn/trainer/tests.rs b/crates/ml/src/trainers/dqn/trainer/tests.rs index 28f5ac9ef..388d8fc94 100644 --- a/crates/ml/src/trainers/dqn/trainer/tests.rs +++ b/crates/ml/src/trainers/dqn/trainer/tests.rs @@ -115,13 +115,16 @@ async fn test_feature_vector_to_state() { ); let state = state.unwrap(); - // State dimension is 45 (42 market + 3 portfolio) - // - Market features: 0-41 (42 features) - // - Portfolio features: 42-44 (3 features, populated by PortfolioTracker) + // State dimension depends on whether OFI (MBP-10) data dirs are configured: + // - Without OFI: 45 = 42 market + 3 portfolio + // - With OFI: 53 = 42 market + 8 OFI + 3 portfolio + // Smoketest TOML sets mbp10_data_dir, so OFI is enabled. + let expected_dim = if trainer.hyperparams.mbp10_data_dir.is_empty() { 45 } else { 53 }; assert_eq!( state.dimension(), - 45, - "State dimension should be 45 (42 market + 3 portfolio features)" + expected_dim, + "State dimension mismatch (OFI enabled={})", + !trainer.hyperparams.mbp10_data_dir.is_empty() ); } diff --git a/crates/ml/src/training_profile.rs b/crates/ml/src/training_profile.rs index 3298e8843..901d2f661 100644 --- a/crates/ml/src/training_profile.rs +++ b/crates/ml/src/training_profile.rs @@ -1088,13 +1088,13 @@ mod tests { // [training] values must have been applied assert_eq!(hp.epochs, 200); - assert_eq!(hp.batch_size, 1024); + assert_eq!(hp.batch_size, 8192); assert!((hp.learning_rate - 0.0001).abs() < 1e-10); // OFI MBP-10 data dir should be set in production profile assert_eq!( hp.mbp10_data_dir.as_str(), - "/mnt/training-data/futures-baseline-mbp10", + "/data/futures-baseline-mbp10", "dqn-production profile must wire mbp10_data_dir" ); } @@ -1350,7 +1350,7 @@ mod tests { // [training] section assert_eq!(hp.epochs, 200); - assert_eq!(hp.batch_size, 1024); + assert_eq!(hp.batch_size, 8192); assert!((hp.learning_rate - 0.0001).abs() < 1e-10); assert!((hp.gamma - 0.99).abs() < 0.001); assert!((hp.reward_scale - 1.0).abs() < 0.01);