// crates/ml/src/cuda_pipeline/q_var_mag_ema_compute_kernel.cu
//
// SP9 (Fix 37, 2026-05-03): GPU producer for the historical EMA baseline of
// magnitude-branch Q-variance. Drives the self-relative `base_floor` ratio
// in `kelly_warmup_floor_compute_kernel.cu` per
// `pearl_controller_anchors_isv_driven.md` (signal-driven anchor — no
// hardcoded 0.5 half-Kelly constant).
//
// Reads `ISV[FLATNESS_BASE+1=207]` (the SP5 Pearl 2 magnitude-branch flatness
// signal). Writes that observation to `scratch_buf[scratch_idx]`.
//
// Downstream `apply_pearls_ad_kernel` chains:
//   - Pearl A (sentinel 0 at fold boundary → first observation replaces slot)
//   - Pearl D (Wiener-optimal α derived from variance ratio at steady state)
// → ISV[Q_VAR_MAG_EMA_INDEX=331].
//
// The SP9 warmup_floor consumer reads BOTH ISV[207] (current) and ISV[331]
// (EMA). Their ratio is the self-relative `base_floor` — when current
// q_var_mag exceeds its historical EMA the network is learning to
// distinguish magnitudes and the floor relaxes; when it drops below,
// safety dominates.
//
// Single-block, single-thread cold-path kernel. No atomicAdd; no shared
// memory; `__threadfence_system()` after the write.

#include <cuda_runtime.h>

extern "C" __global__ void q_var_mag_ema_compute(
    const float* __restrict__ isv_signals,
    int   q_var_mag_isv_index,    // FLATNESS_BASE+1 = 207
    float* __restrict__ scratch_buf,
    int   scratch_idx
) {
    if (blockIdx.x != 0 || threadIdx.x != 0) return;

    float q_var_mag = isv_signals[q_var_mag_isv_index];
    /* Defensive clamp — variance is nonnegative; sentinel-bootstrap path
     * relies on `step_obs == 0` to short-circuit, so we leave 0 as 0
     * (Pearl A's `prev == 0` cold-start branch fires the first observation
     * replacement). */
    if (q_var_mag < 0.0f) q_var_mag = 0.0f;

    scratch_buf[scratch_idx] = q_var_mag;
    __threadfence_system();
}
