diff --git a/ml/src/trainers/dqn.rs b/ml/src/trainers/dqn.rs index 551306b2d..5814ac3a4 100644 --- a/ml/src/trainers/dqn.rs +++ b/ml/src/trainers/dqn.rs @@ -1262,13 +1262,9 @@ impl DQNTrainer { // WAVE 9-11: Track Q-value range for production monitoring monitor.track_q_value_range(q_value); - // WAVE 11 FIX: Update epsilon per training step (not per epoch) - // This ensures epsilon decays properly: epsilon_start * (epsilon_decay ** step) - // With epsilon_decay=0.995, epsilon reaches 0.05 at step ~2,977 (~2.1 epochs) - { - let mut agent = self.agent.write().await; - agent.update_epsilon(); - } + // BUG #29 FIX: Epsilon decay moved to per-epoch (see line ~1340) + // Previous per-batch decay caused premature exploration collapse in short hyperopt trials + // With batch_size=72, epsilon hit floor (0.05) after 2.1 epochs, freezing at 2.2% diversity }, Err(e) => { // Log error but continue training (some batches may fail due to sampling issues) @@ -1331,6 +1327,14 @@ impl DQNTrainer { epoch_duration.as_secs_f64() ); + // BUG #29 FIX: Update epsilon once per epoch (not per batch) + // This ensures consistent exploration across different batch sizes + // With epsilon_decay=0.995, after 15 epochs: 0.3 × (0.995^15) = 0.2783 (27.8% exploration) + { + let mut agent = self.agent.write().await; + agent.update_epsilon(); + } + // WAVE 9-11: Log Q-value range for production monitoring if train_step_count > 0 { info!(