Replace the evaluator's independent CublasForward with QValueProvider
trait that routes Q-value computation through the trainer's graphed
CublasForward. This eliminates the separate cuBLAS handle that caused
evaluation non-determinism.
Architecture:
- QValueProvider trait in q_value_provider.rs (compute_q_values_to)
- FusedTrainingCtx implements it (chunks through trainer batch_size=64)
- GpuDqnTrainer::compute_q_values_graphed captures eval forward in
CUDA Graph (cuBLAS forward + compute_expected_q) on first call
- Pre-captured at deterministic point (right after mega graph)
- evaluate_dqn_graphed takes &mut dyn QValueProvider (mandatory)
Cleanup (-398 lines):
- Deleted evaluator's internal CublasForward + all chunked scratch buffers
- Deleted compute_q_values (non-graphed), flatten_weights_for_cublas,
ensure_cublas_ready, compute_backtest_param_sizes
- Deleted evaluate_dqn (fallback path)
- Removed dead imports and stale comments
Training: fully bit-identical across runs (CUDA Graph replay).
Evaluation: deterministic within process (graph replay), minor
variation across processes (cublasLtMatmul capture non-determinism).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>