fix: backtracking checkpoint save + branch Adam reset bugs

1. Checkpoint save: improvement_rate used sharpe_history.last() which is
   the CURRENT epoch (just pushed). Always compared current to itself → 0.
   Fix: use sharpe_history[len-2] (previous epoch).

2. Branch Adam reset: required !checkpoints.is_empty() but branch reset
   doesn't USE checkpoints — it just zeros momentum in-place. Removed
   the checkpoint guard so the lightweight fix fires even without saved
   checkpoints.

Both bugs prevented backtracking from ever acting in train-l7g9t despite
detecting 6 consecutive frozen epochs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-15 15:06:07 +02:00
parent f17867784b
commit 6d8a38f0b4

View File

@@ -2457,7 +2457,12 @@ impl DQNTrainer {
}
// 2. Save checkpoint when improving
let prev_sharpe = self.sharpe_history.last().copied().unwrap_or(0.0) as f32;
// Use second-to-last sharpe (last is current epoch, already pushed before this runs)
let prev_sharpe = if self.sharpe_history.len() >= 2 {
self.sharpe_history[self.sharpe_history.len() - 2] as f32
} else {
0.0
};
let improvement_rate = val_sharpe_f32 - prev_sharpe; // per epoch
if improvement_rate > 0.01 && !self.backtracking.route_active {
self.save_backtracking_checkpoint(epoch, improvement_rate, val_sharpe_f32)?;
@@ -2522,10 +2527,10 @@ impl DQNTrainer {
// reset (zeroes m/v for indices 8-41, preserves trunk momentum). This may break
// Adam fixed point without changing weights. Give it 3 epochs to take effect.
// Full rewind triggers at plateau_threshold + 3.
// Branch Adam reset doesn't need checkpoints — it's a lightweight in-place fix.
if self.backtracking.plateau_epochs == self.backtracking.plateau_threshold
&& !self.backtracking.route_active
&& epoch.saturating_sub(self.backtracking.last_rewind_epoch) >= self.backtracking.min_rewind_interval
&& !self.backtracking.checkpoints.is_empty()
{
if let Some(ref mut fused) = self.fused_ctx {
if let Err(e) = fused.reset_branch_adam_momentum() {