Files
foxhunt/crates
jgrusewski aa16ca31f2 diag(policy-quality): finish Tasks 0.3 + 0.6 partial wirings
Task 0.3 (Track 1 magnitude):
  * q_mag_full/half/quarter: plumbed via GpuDqnTrainer::q_magnitude_bucket_means()
    → FusedTrainingCtx::q_magnitude_bucket_means() → HEALTH_DIAG. Phase-0
    returns [0.0; 3]; per-mag Q reduction kernel deferred per plan §0.3 step 2
    (goal here is the accessor chain, swap-in without touching emit formatting).
  * var_scale_mean: STUB 0.0 — kernel computes `1/(1+sqrt(Var[Q]))` per-sample
    inside experience_env_step but does not persist to a device buffer; it is
    consumed in-place to shrink effective_max_pos. Exposing requires a
    dedicated per-sample output buffer + launch arg + kernel write; deferred
    to Phase 1+. Documented in code.
  * kelly_f_mean / avg_win_ratio: REAL — computed host-side from
    self.trade_stats_history.last() using the SAME formula the kernel uses
    (b = avg_win/avg_loss, kelly = (b·p − (1−p))/b clamped [0,1] × 0.5
    for half-Kelly; avg_win_ratio = (sum_wins/win_count) /
    max(sum_losses/loss_count, 0.001) per plan formula line 239).
    One-epoch lag (trade_stats_history is appended later in the same
    epoch body); zero until first epoch's stats land. Documented in code.

Task 0.6 (Track 1 noisy):
  * vsn_mag / vsn_dir: REAL per-branch — mean |w| across each branch's VSN
    projection weight pair (tensors 26..34 grouped by branch:
    26/27=dir, 28/29=mag, 30/31=order, 32/33=urg). The live VSN gate mask is
    computed per-sample inside variable_select_bottleneck and consumed
    immediately, not materialized into a device buffer we can cheaply read;
    projection-weight mean is the closest stable H7 surrogate. Documented
    in accessor rustdoc. Higher-fidelity measurement would require a
    per-sample mask output buffer following the Task 0.5 pattern — deferred.
  * drift_mag / drift_dir: REAL per-branch — RMS ‖target_w − online_w‖ across
    each branch's 4 weight tensors (indices 8..12 dir, 12..16 mag, 16..20
    order, 20..24 urg). Host-computed cold path via two memcpy_dtoh + normal
    Vec<f32> reduce loops; stream-sync'd before read. NO atomics (project rule).
    ~2.7 MB × 2 DtoH per epoch, negligible diagnostic cost.

NoisyNets sigma_mag/sigma_dir already wired in 999bb2fa0 — preserved untouched.

Accessor chain (mirrors Task 0.4 grad_ratio_mag_dir pattern):
  * GpuDqnTrainer::per_branch_target_drift() -> Result<[f32; 4], MLError>
  * GpuDqnTrainer::per_branch_vsn_mean()     -> Result<[f32; 4], MLError>
  * GpuDqnTrainer::q_magnitude_bucket_means()-> [f32; 3]  (plumbing stub)
  * FusedTrainingCtx wrappers → delegate, fallback to zeros on MLError.
  * training_loop.rs HEALTH_DIAG block: populate slots via
    self.fused_ctx.as_ref().map(|f| f.…).unwrap_or(…) — same pattern
    used for grad_ratio_mag_dir.

HEALTH_DIAG `mag` and `noisy` groups now carry real signal (or plan-sanctioned
plumbing stubs for the q_mag_* / var_scale slots documented in commit + code).
2026-04-21 23:39:08 +02:00
..