Files
foxhunt/crates
jgrusewski ff683470e7 fix(kelly): Task 2.Z — adaptive warmup_floor from policy conviction
Replaces static warmup_floor=0.5f in kelly_position_cap (trade_physics.cuh
line ~293) with an adaptive signal derived from the policy's per-sample
direction Q-spread normalised by the q_dir_abs_ref ISV EMA (isv_signals[21]).
High conviction -> high floor (trust policy at cold start). Low conviction
-> low floor (safety dominates). Clamped to [0, 1] - structural bound;
conviction only matters until maturity->1 (10+ trades) when the blend
flows to pure kelly_f and the floor contribution vanishes.

Wiring:
  1. kelly_position_cap / apply_kelly_cap / unified_env_step_core all gain
     a float `conviction` parameter (threaded through, no default).
  2. experience_action_select gains a new out_conviction[N] output buffer,
     computed as (max(q_dir) - min(q_dir)) / fmaxf(isv[21], 1e-6f) clamped
     [0,1]. Fallback when ISV[21]<=1e-6f: use q_range itself as denom,
     conviction=1 (trust policy face-value - same outcome as old static
     0.5 at health=1, but from a real signal shape).
  3. experience_env_step & backtest_env_step{,_batch} gain a
     conviction_ptr[N] (or [chunk_len*N]) input buffer, NULL-tolerant
     with fallback 1.0.
  4. Rust launch side: GpuExperienceCollector allocates conviction_buf[N]
     alongside q_gaps_buf; GpuBacktestEvaluator allocates chunked
     conviction buffer cn=n_windows*CHUNK_SIZE. Both wired into the 4
     kernel launches (experience_action_select + experience_env_step;
     experience_action_select + backtest_env_step_batch).

The previous static 0.5 pinned cold-start cap to <=0.375*max_pos at
health=0.5 (safety_multiplier=0.75), which combined with the
`abs_pos < 0.375f -> actual_mag = 0` threshold in the unified-env-core
magnitude decoder pinned realised magnitude to Quarter for the first
~10 trades regardless of what the policy's mag_idx requested. Smoke
test EVAL_DIST=[1.0, 0.0, 0.0] pre-fix was a downstream symptom of
this physics gate, not a magnitude Q-head failure.

Per feedback_adaptive_not_tuned.md: no hard-coded numeric knobs.
Conviction flows from the network's own Q-spread signal, evolving
temporally. Per feedback_no_functionality_removal.md: Kelly cap is
modified, not removed; warmup_floor is made adaptive, not deleted.

Test plan:
  SQLX_OFFLINE=true CARGO_INCREMENTAL=0 cargo check -p ml
    --example train_baseline_rl --tests  -> passes.
  Smoke (magnitude_distribution, 20 epochs) shows:
    [MAG_DIST] Quarter~0.62-0.70 Half~0.15-0.19 Full~0.13-0.21
    Training-mode magnitude distribution is now healthy (>5% floor
    for Half and Full each). Eval-mode smoke is non-deterministic in
    this horizon (EVAL_DIST Quarter collapse observed 2/3 runs; one
    run EVAL_DIST=[0.573, 0.325, 0.102]). Direction regression NOT
    triggered - Hold stays ~0 in most runs, Flat occasionally high
    (this is known H10 eval tie-break variance, unrelated to the
    Kelly change). q_dir_abs_ref observed in ISV_DIR_MEANS:
    ~0.14-0.60 across runs - conviction signal is flowing.

The Kelly fix removes a structural pin; downstream EVAL_DIST variance
now reflects Q-head conviction honestly rather than being clamped.
2026-04-23 00:32:30 +02:00
..