//! SP11 — Reward-subsystem controller ISV slot constants.
//!
//! Slots [340..367) populated by the SP11 controller chain:
//!   - 6 component weights [340..346)
//!   - 4 controller scalar outputs [346..350)
//!   - 2 val-sharpe canaries [350..352)
//!   - 6 mag-ratio canaries [352..358)
//!   - 1 saboteur engagement (358)
//!   - 1 PnL magnitude EMA (359) — total reward magnitude (PopArt's input)
//!   - 1 PopArt-component-specific magnitude EMA (360) — B1b fix-up
//!   - 6 per-reward-component variance EMAs [361..367) — B1b smoke-recovery
//!     (z-score normalization for the mag-ratio canary)
//!
//! Spec: docs/superpowers/specs/2026-05-04-sp11-reward-as-controlled-subsystem.md
//! Pearl: pearl_reward_as_controlled_subsystem.md

// Component weights (controller outputs, consumed by reward shaping kernels)
pub const REWARD_POPART_WEIGHT_INDEX:    usize = 340;
pub const REWARD_CF_WEIGHT_INDEX:        usize = 341;
pub const REWARD_TRAIL_WEIGHT_INDEX:     usize = 342;
pub const REWARD_MICRO_WEIGHT_INDEX:     usize = 343;
pub const REWARD_OPP_COST_WEIGHT_INDEX:  usize = 344;
pub const REWARD_BONUS_WEIGHT_INDEX:     usize = 345;

// Controller scalar outputs
pub const CURIOSITY_PRESSURE_INDEX:      usize = 346;
pub const SABOTEUR_INTENSITY_MULT_INDEX: usize = 347;
pub const REWARD_WEIGHT_FLOOR_INDEX:     usize = 348;
pub const CURIOSITY_BOUND_INDEX:         usize = 349;

// Canaries — val-sharpe trend + variance
pub const VAL_SHARPE_DELTA_EMA_INDEX:    usize = 350;
pub const VAL_SHARPE_VAR_EMA_INDEX:      usize = 351;

// Canaries — per-component reward-magnitude ratios (6 contiguous slots).
// Source: REWARD_POPART_EMA_INDEX..+6 (existing per-component reward
// magnitude EMAs from reward_component_ema_kernel). Spec §3.3.1 said
// "grad EMA" but the SP4 grad-balancer is per-branch (4 slots), not
// per-reward-component. Per `feedback_trust_code_not_docs`: code wins,
// terminology corrected. Semantics for the controller are equivalent —
// "which component contributes most to total reward" maps the same way
// in the winner_weight / diversifier_weight blend.
pub const REWARD_COMPONENT_MAG_RATIO_BASE: usize = 352;
pub const REWARD_COMPONENT_MAG_RATIO_COUNT: usize = 6;

// Canaries — saboteur + PnL signal scale
pub const SABOTEUR_ENGAGEMENT_RATE_INDEX: usize = 358;
pub const PNL_REWARD_MAGNITUDE_EMA_INDEX: usize = 359;

// Canary — popart-component-specific magnitude EMA (B1b fix-up, 2026-05-04).
//
// Pre-SP11 the SP4 reward_component_ema kernel wrote `|reward_components_per_sample[+0]|`
// EMA into ISV[REWARD_POPART_EMA_INDEX=63]. That slot was overloaded:
// it served BOTH as PopArt's normalisation-target input AND as a stand-in
// for popart-component-specific magnitude. Pre-SP11 reward composition was
// inline accumulation (popart was the dominant component, so the two values
// collapsed). B1b's structural decomposition (per-component locals + Σ w_i × r_i)
// surfaces the contamination: the SP11 mag-ratio canary reading slot 63
// sees the inflated TOTAL-reward magnitude as "popart's signal" and over-
// weighs popart (w_pop ≈ 2.0) → 10× sharpe drop in B1b smoke.
//
// Resolution: a separate ISV slot for popart-component-specific magnitude.
// Producer is `popart_component_ema_kernel.cu` chained through
// `apply_pearls_ad_kernel` (n_slots=1). Slot 63 stays as PopArt's input
// (= total reward magnitude), preserving the pre-SP11 invariant. Spec
// §4 amendment "Why slot 360".
pub const POPART_COMPONENT_MAG_EMA_INDEX: usize = 360;

/// Per-reward-component variance EMA base. 6 slots [361..367) for
/// {popart, cf, trail, micro, opp_cost, bonus} variance EMAs. Computed
/// alongside their magnitude EMAs (slots 360, 64..68) via Welford's
/// online algorithm in popart_component_ema_kernel + reward_component_ema_kernel.
/// Read by reward_component_mag_ratio_compute_kernel for z-score
/// normalization (z[c] = mag[c] / max(sqrt(var[c]), EPS_DIV)).
///
/// Why z-score (B1b smoke-recovery, 2026-05-04): the linear mag-ratio
/// formula `winner_weight = mag_ratio` amplified whichever reward
/// component had the largest intrinsic magnitude. Popart (trade P&L) is
/// O(100) per fire; cf/trail/micro/opp_cost/bonus are O(0.1-2). Result:
/// `w_pop` saturated toward MAX_WEIGHT, curiosity_b exploded, sharpe
/// collapsed. Z-score makes ratios scale-invariant — every component
/// contributes "shares of own scale" rather than "shares of absolute
/// magnitude". The controller's redistribution logic works correctly
/// when it sees ratios ≈ 1/6 each at stability.
///
/// Layout:
///   [361] = popart variance EMA (paired with mag at slot 360)
///   [362] = cf       variance EMA (paired with mag at slot 64)
///   [363] = trail    variance EMA (paired with mag at slot 65)
///   [364] = micro    variance EMA (paired with mag at slot 66)
///   [365] = opp_cost variance EMA (paired with mag at slot 67)
///   [366] = bonus    variance EMA (paired with mag at slot 68)
///
/// FoldReset sentinel 0; Pearl A bootstraps from the first observation
/// alongside the magnitude EMAs (the magnitudes already paired with
/// their per-fold sentinel-bootstrap path; the variance partners share
/// it). NOT cross-fold persistent — variances reset each fold so the
/// canary tracks the new fold's reward-component scale distribution.
pub const REWARD_COMPONENT_VAR_EMA_BASE:  usize = 361;
pub const REWARD_COMPONENT_VAR_EMA_COUNT: usize = 6;

// Invariant-1 anchors (rate-limiters, NOT regime thresholds).
//
// Per `feedback_isv_for_adaptive_bounds`: every adaptive bound lives on
// ISV. The constants below are the few exceptions allowed by Invariant-1
// — they are numerical-stability anchors (epsilon floors), structural
// fractions of signal-driven quantities (curiosity-bound = 0.3 × PnL EMA),
// and rate-limiter clamps that bound the saboteur multiplier output. Each
// is documented in the SP11 spec §3.4.2 (Invariant-1 carve-out table).
pub const SP11_EPS_DIV: f32 = 1e-6;
pub const SP11_WEIGHT_HARD_FLOOR: f32 = 0.01;
pub const SP11_SABOTEUR_MIN: f32 = 0.5;
pub const SP11_SABOTEUR_MAX: f32 = 2.0;
pub const SP11_CURIOSITY_PERMANENT_FRACTION: f32 = 0.2;
pub const SP11_CURIOSITY_BOUND_FRACTION: f32 = 0.3;
pub const SP11_WEIGHT_FLOOR_FRACTION: f32 = 0.5;
pub const SP11_ENGAGEMENT_FLOOR: f32 = 0.1;

pub const SP11_SLOT_BASE: usize = 340;
pub const SP11_SLOT_END:  usize = 367;
pub const SP11_PRODUCER_COUNT: usize = SP11_SLOT_END - SP11_SLOT_BASE;

/// Salt added to `config.seed` when seeding the novelty SimHash projection
/// matrix init kernel. Co-located here so the seed-derivation path is
/// reproducible from a single source of truth. Consumed by the launcher
/// `launch_novelty_simhash_proj_init` (added in Task A2 alongside the
/// projection buffer).
pub const SP11_PROJ_SEED_SALT: u64 = 0x_5511_0001;
