/* seed_step_counter_update — GPU-driven seed-phase progress tracker.
 *
 * Plan 3 Task 8 (B.3 GPU-only seeded warm-start).
 *
 * Single-thread cold-path kernel launched after every
 * `collect_experiences_gpu` call, alongside the other Plan 3 EMA producers.
 * Increments ISV[SEED_STEPS_DONE_INDEX] by `n_samples_this_step`, capped at
 * ISV[SEED_STEPS_TARGET_INDEX]. Computes the seed fraction
 * `frac = max(0, 1 - done/target)` (smoothly decays 1→0 as the seed phase
 * completes) and EMA-tracks it into ISV[SEED_FRAC_EMA_INDEX] with the
 * adaptive-rate convention shared with the other Plan 3 producers
 * (α = α_base × (1 + 0.5 × |clamp(sharpe, ±2)|)).
 *
 * SEED_FRAC_EMA is the consumer signal for Task 9 (CQL α ramp). When
 * frac ≈ 1 (fully in seed phase), CQL α decays toward 0 (no pessimism on
 * exploration data); as frac → 0, CQL α ramps to its config-final value.
 */

#include <cuda_runtime.h>

extern "C" __global__ void seed_step_counter_update(
    float* __restrict__ isv_out,        /* ISV bus [ISV_TOTAL_DIM] */
    int    seed_done_idx,                /* = SEED_STEPS_DONE_INDEX = 83 */
    int    seed_target_idx,              /* = SEED_STEPS_TARGET_INDEX = 82 */
    int    seed_frac_idx,                /* = SEED_FRAC_EMA_INDEX = 84 */
    int    sharpe_ema_idx,               /* = SHARPE_EMA_INDEX = 22 */
    float  alpha_base,                   /* base EMA rate (e.g. 0.05) */
    int    n_samples_this_step           /* number of (i,t) experience samples this collect */
) {
    if (threadIdx.x != 0 || blockIdx.x != 0) return;

    const float target    = isv_out[seed_target_idx];
    const float prev_done = isv_out[seed_done_idx];
    const float new_done  = fminf(target, prev_done + (float)n_samples_this_step);
    isv_out[seed_done_idx] = new_done;

    /* Smoothly decay seed fraction from 1.0 (cold-start) toward 0 as DONE
     * approaches TARGET. Floor 1.0 in denominator avoids div-by-zero when
     * target=0 (smoke configs may set this — whole seed phase becomes
     * inert, frac→0 immediately). */
    const float new_frac = fmaxf(0.0f, 1.0f - new_done / fmaxf(1.0f, target));

    /* Adaptive α matches Task 3 (trade_rate_ema) / Task 4 (plan_threshold)
     * convention. Higher-Sharpe epochs update the estimate faster. */
    const float sharpe = fmaxf(-2.0f, fminf(2.0f, isv_out[sharpe_ema_idx]));
    const float alpha  = alpha_base * (1.0f + 0.5f * fabsf(sharpe));
    const float prev_frac_ema = isv_out[seed_frac_idx];
    isv_out[seed_frac_idx] = (1.0f - alpha) * prev_frac_ema + alpha * new_frac;
}
