/* SP12 v3 reward-math GPU oracle test kernel.
 *
 * Standalone test wrapper that exercises the three device-inline reward
 * composition functions added to `trade_physics.cuh` for SP12 v3:
 *   - compute_asymmetric_capped_pnl
 *   - compute_min_hold_penalty
 *   - compute_lump_sum_opp_cost
 *
 * One thread per kernel launch is sufficient — these functions are pure
 * register-only arithmetic with no shared state. The wrapper mirrors the
 * production kernel's call sites bit-for-bit so the tests verify the
 * exact math the production reward chain executes (no CPU reference impl
 * per `feedback_no_cpu_test_fallbacks`).
 *
 * Outputs go to mapped-pinned buffers (cuMemHostAlloc DEVICEMAP|PORTABLE)
 * with a `__threadfence_system()` before thread exit so the host can read
 * via `read_volatile` after a stream sync. Same pattern as
 * `thompson_test_kernel.cu` and `sp4_histogram_p99_test_kernel.cu`.
 *
 * Test-only: no production callers. Cubin built by `crates/ml/build.rs`
 * (kernel name `sp12_reward_math_test_kernel`).
 */

#include <cuda_runtime.h>
#include "trade_physics.cuh"  /* compute_asymmetric_capped_pnl, compute_min_hold_penalty, compute_lump_sum_opp_cost */

extern "C" __global__ void sp12_reward_math_test_kernel(
    /* ── asymmetric cap inputs ── */
    const float* __restrict__ in_base_reward,
    float neg_cap,
    float pos_cap,
    float* __restrict__ out_capped_pnl,
    /* ── min-hold penalty inputs ── */
    const float* __restrict__ in_hold_time_mh,
    float min_hold_target,
    float min_hold_temperature,
    float min_hold_penalty_max,
    float* __restrict__ out_min_hold_penalty,
    /* ── lump-sum opp_cost inputs ── */
    float shaping_scale,
    float holding_cost_rate,
    const float* __restrict__ in_position,
    const float* __restrict__ in_hold_time_oc,
    float* __restrict__ out_opp_cost
) {
    /* Single-thread launch — the wrapper has no parallelism to exploit
     * (each test invocation drives one (input, expected-output) pair). */
    if (threadIdx.x != 0 || blockIdx.x != 0) return;

    out_capped_pnl[0] = compute_asymmetric_capped_pnl(
        in_base_reward[0], neg_cap, pos_cap
    );
    out_min_hold_penalty[0] = compute_min_hold_penalty(
        in_hold_time_mh[0], min_hold_target, min_hold_temperature, min_hold_penalty_max
    );
    out_opp_cost[0] = compute_lump_sum_opp_cost(
        shaping_scale, holding_cost_rate, in_position[0], in_hold_time_oc[0]
    );

    /* Make all three writes PCIe-visible to host pointers (mapped-pinned
     * buffers). The host reads via `read_volatile` after a stream sync;
     * the fence guarantees the writes have actually drained from the GPU
     * write buffers before the sync returns. */
    __threadfence_system();
}
