From 5bc712478ecc8c12c422993789fbaee015f5bc4f Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Mon, 20 Apr 2026 21:38:53 +0200 Subject: [PATCH] =?UTF-8?q?refactor(A2):=20production=20=CE=B1=3D0.1,=20te?= =?UTF-8?q?sts=20opt=20in=20to=20=CE=B1=3D0.3=20via=20with=5Falpha()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LearningHealth::new() now uses α=0.1 (the production-appropriate ~10-sample EMA window for 80-100 epoch runs). Tests that need to reach threshold assertions inside a 5-iteration loop (warmup=3 + 2 EMA steps) use LearningHealth::with_alpha(0.3) instead of bending production behaviour to satisfy test convenience. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ml/src/cuda_pipeline/learning_health.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/ml/src/cuda_pipeline/learning_health.rs b/crates/ml/src/cuda_pipeline/learning_health.rs index 67389d251..38191a55e 100644 --- a/crates/ml/src/cuda_pipeline/learning_health.rs +++ b/crates/ml/src/cuda_pipeline/learning_health.rs @@ -86,12 +86,22 @@ pub struct LearningHealth { } impl LearningHealth { + /// Production constructor. α=0.1 gives ~10-sample EMA window — appropriate + /// smoothing for an 80–100 epoch training run where we want health to be + /// responsive but not whipsaw on single-epoch noise. pub fn new() -> Self { + Self::with_alpha(0.1) + } + + /// Test/tuning constructor with an explicit α. Tests use higher α (≈0.3) + /// to satisfy threshold assertions inside a 5-iteration (warmup + 2 EMA + /// steps) test loop; production code should use `new()`. + pub fn with_alpha(alpha: f32) -> Self { Self { value: 0.5, // neutral start epoch: 0, components: NormalizedComponents::default(), - ema_alpha: 0.3, + ema_alpha: alpha, warmup_epochs: 3, } } @@ -144,7 +154,9 @@ mod tests { grad_consistency: -0.3, // gradients contradict spectral_gap: 50.0, // rank 1 }; - let mut health = LearningHealth::new(); + // Tests use α=0.3 to reach thresholds inside the short 5-iteration loop; + // production new() uses α=0.1. + let mut health = LearningHealth::with_alpha(0.3); // Skip warmup for _ in 0..5 { health.update(&raw); } assert!(health.value <= 0.3, "Collapsed state should give health <= 0.3, got {}", health.value); @@ -161,7 +173,7 @@ mod tests { grad_consistency: 0.9, // consistent direction spectral_gap: 1.5, // balanced rank }; - let mut health = LearningHealth::new(); + let mut health = LearningHealth::with_alpha(0.3); for _ in 0..5 { health.update(&raw); } assert!(health.value >= 0.7, "Healthy state should give health >= 0.7, got {}", health.value); } @@ -173,7 +185,7 @@ mod tests { grad_norm: 50_000.0, ens_disagreement: 0.0, grad_consistency: -0.5, spectral_gap: 100.0, }; - let mut health = LearningHealth::new(); + let mut health = LearningHealth::with_alpha(0.3); // First 3 updates are warmup — should stay at 0.5 for _ in 0..3 { let v = health.update(&raw);