Part A of pre-L40S cleanup.
1. Wire td_error batch mean into ISV scratch (gpu_dqn_trainer.rs):
`launch_loss_reduce` now runs the generic `c51_loss_reduce` kernel a
second time over `td_errors_buf` into `td_error_scratch_dev_ptr`.
ISV[2] (TD-error EMA in `isv_signal_update`) was previously reading
a zero-initialised scratch and accumulated a constant-zero signal.
This was a genuinely missing kernel writeback — the C51 loss kernel
was already emitting per-sample |TD-error| into `td_errors_buf`
(c51_loss_kernel.cu:1096), it just wasn't being batch-reduced.
Reuses the existing `c51_loss_reduce` (generic mean-reduction, single
block, deterministic) rather than adding a new kernel — no new CUDA
surface, no ABI change.
2. Remove 2 stale TODOs from batched_backward.rs docstrings that
described a migration that's actually complete:
- Module docstring said "dqn_backward_kernel (atomicAdd path)
remains active" — the atomicAdd kernel has been removed; cuBLAS
backward is wired via launch_cublas_backward.
- `backward_full` docstring said "gated behind TODO" — the function
is actively called from the fused training step.
3. Rewrite 2 ISV scratch field comments as declarative: td_error_scratch
is now wired (as per change 1); ensemble_var_scratch remains
zero-initialised and its comment honestly describes that consumers
(ISV[3] and [4]) treat it as unavailable. Per feedback_no_todo_fixme.md,
replaces the TODO(isv) markers with declarative descriptions of
current behaviour. Future wiring is tracked in the plan, not in code
aspirational markers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>