From 8be3d05ab7ee16559152732596da96bdaaf96bf9 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Mon, 20 Apr 2026 20:59:23 +0200 Subject: [PATCH] =?UTF-8?q?fix(D7/N7):=20zero=20out=5Fq=5Fgaps=20during=20?= =?UTF-8?q?contrarian=20mode=20=E2=80=94=20prevents=20full-conviction=20si?= =?UTF-8?q?zing=20on=20argmin=20trades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses reviewer's IMPORTANT flag: the conviction Q-gap was not sign-flipped when contrarian_active, so downstream env_step would size contrarian (argmin) positions with maximum conviction, amplifying losses. During contrarian override, set out_q_gaps=0 so those trades size minimally — the override is deliberate and temporary; we don't want to compound it with aggressive position sizing. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/cuda_pipeline/experience_kernels.cu | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/ml/src/cuda_pipeline/experience_kernels.cu b/crates/ml/src/cuda_pipeline/experience_kernels.cu index b74d69f95..42051e5bb 100644 --- a/crates/ml/src/cuda_pipeline/experience_kernels.cu +++ b/crates/ml/src/cuda_pipeline/experience_kernels.cu @@ -1010,13 +1010,22 @@ extern "C" __global__ void experience_action_select( /* Output Q-gap for conviction-based position sizing. * Q-gap = Q(best_direction) - Q(Flat). Higher = more conviction. - * Used by env_step to scale target_position. */ + * Used by env_step to scale target_position. + * + * D7/N7: During contrarian override, the action selected is argmin rather + * than argmax. The raw Q(best) - Q(Flat) gap would mislead the position + * sizer into full conviction for what's actually the "deliberately wrong" + * action. Zero out the gap so contrarian trades size minimal. */ if (out_q_gaps != NULL) { - int flat_idx = 3; /* Flat = index 3 for direction(4): Short(0)/Hold(1)/Long(2)/Flat(3) */ - float q_best = q_b0[argmax_n(q_b0, b0_size)]; - float q_flat = q_b0[flat_idx]; - float gap = q_best - q_flat; - out_q_gaps[i] = (gap > 0.0f) ? gap : 0.0f; + if (contrarian_active != 0) { + out_q_gaps[i] = 0.0f; + } else { + int flat_idx = 3; /* Flat = index 3 for direction(4): Short(0)/Hold(1)/Long(2)/Flat(3) */ + float q_best = q_b0[argmax_n(q_b0, b0_size)]; + float q_flat = q_b0[flat_idx]; + float gap = q_best - q_flat; + out_q_gaps[i] = (gap > 0.0f) ? gap : 0.0f; + } } }