//! Formal classification of every piece of training-time state by reset lifecycle.
//! See `docs/superpowers/specs/2026-04-24-dqn-v2-unified-design.md` §4.A.1.

// Slot-name constants (LOSS_CAP_INDEX, ALPHA_EMA_INDEX, …) are referenced
// in the per-entry `description` string literals below for documentation;
// no code path imports the symbols. The previous use-block was a stale
// remnant from when the registry built its entries programmatically.

/// Reset lifecycle category for a piece of training-time state.
///
/// See `docs/superpowers/specs/2026-04-24-dqn-v2-unified-design.md` §4.A.1.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResetCategory {
    /// Cleared at fold boundary.
    FoldReset,
    /// Cleared at validation-window boundary.
    WindowReset,
    /// Anneals toward bootstrap value over `decay_bars` bars at fold boundary.
    SoftReset { decay_bars: u32 },
    /// Survives across folds (learned weights).
    TrainingPersist,
    /// Structurally fixed across runs; fail-fast on mismatch. No migration path exists.
    SchemaContract,
}

/// One entry in the reset registry.
#[derive(Debug, Clone, Copy)]
pub struct RegistryEntry {
    pub name: &'static str,
    pub category: ResetCategory,
    /// Short description — what this state represents. Used in diagnostic dumps.
    pub description: &'static str,
}

/// Typed registry classifying every piece of training-time state.
///
/// Populated at construction; read-only thereafter. Adding new state requires
/// adding a new entry here in the same commit that introduces the state
/// (per Invariant 2 Wire-It-Up).
#[derive(Debug)]
pub struct StateResetRegistry {
    entries: Vec<RegistryEntry>,
}

impl StateResetRegistry {
    /// Build the registry with all currently-known training state.
    pub fn new() -> Self {
        let entries = vec![
            // ───── Fold-reset state ─────────────────────────────────────
            RegistryEntry {
                name: "kelly_stats",
                category: ResetCategory::FoldReset,
                description: "Per-window Kelly win/loss counters (ps[14..18])",
            },
            RegistryEntry {
                name: "eval_q_mean_ema",
                category: ResetCategory::FoldReset,
                description: "Per-branch Q-mean EMAs in update_eval_v_range",
            },
            RegistryEntry {
                name: "eval_q_std_ema",
                category: ResetCategory::FoldReset,
                description: "Per-branch Q-std EMAs in update_eval_v_range",
            },
            RegistryEntry {
                name: "isv_v_range_slots",
                category: ResetCategory::FoldReset,
                description: "ISV[23..31) — v_center/v_half per branch",
            },
            RegistryEntry {
                name: "isv_learning_health",
                category: ResetCategory::FoldReset,
                description: "ISV[12] — learning_health EMA",
            },
            RegistryEntry {
                name: "isv_sharpe_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[22] — training Sharpe EMA",
            },
            RegistryEntry {
                name: "isv_q_means",
                category: ResetCategory::FoldReset,
                description: "ISV[13..22) — per-direction/magnitude Q-mean EMAs + |Q| refs",
            },
            // ───── IQN readiness gauge (Fix 3 of 3 fold-boundary audit) ─────
            // Three coupled scalars on `GpuDqnTrainer`:
            //   `iqn_loss_initial`: anchor captured on first `update_iqn_readiness`
            //   `iqn_loss_ema`: streaming smoothed loss
            //   `iqn_readiness`: (initial - ema)/initial gauge ∈ [0,1]
            //   plus the pinned-host-mapped device slot read by c51_loss
            //   kernel as CVaR α + by gating consumers.
            // Without fold-boundary reset the anchor stays pinned to the
            // fold-0 epoch-1 IQN loss for the entire run, so the gauge in
            // fold N+1 is computed against a stale baseline. All three names
            // dispatch to the same `reset_iqn_readiness_state` helper.
            RegistryEntry {
                name: "isv_iqn_loss_initial",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.iqn_loss_initial_pinned — fold-anchor for IQN improvement gauge stored in a mapped-pinned scalar; producer is `update_iqn_readiness_kernel` (SP4 Layer C close-out C2, 2026-05-01 — migrated from host-side `f32` field per `feedback_no_cpu_compute_strict`); cold-start sentinel `prev < 1e-12 ⇒ bootstrap` keeps the deleted host formula's semantics. Reset to 0.0 at fold boundary so the new fold's first kernel launch re-enters the bootstrap branch.",
            },
            RegistryEntry {
                name: "isv_iqn_loss_ema",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.iqn_loss_ema_pinned — streaming smoothed IQN loss in a mapped-pinned scalar; producer is `update_iqn_readiness_kernel` (SP4 Layer C close-out C2, 2026-05-01 — migrated from host-side `f32` field per `feedback_no_cpu_compute_strict`); coupled to isv_iqn_loss_initial in the readiness fraction `(initial - ema) / max(initial, 1e-6)`. Reset to 0.0 at fold boundary alongside the anchor so the new fold's first kernel launch reseeds via bootstrap.",
            },
            RegistryEntry {
                name: "isv_iqn_readiness",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.iqn_readiness_pinned (mapped-pinned device slot read by c51_loss_kernel as CVaR α and by IQN gradient-weight gating); produced GPU-side by `update_iqn_readiness_kernel` per training step (SP4 Layer C close-out C2, 2026-05-01) — replaces the prior host-side `(1-α) × prev + α × loss` arithmetic in `update_iqn_readiness` per `feedback_no_cpu_compute_strict`. Reset to 0.0 at fold boundary so the new fold's first `update_iqn_readiness` recaptures the bootstrap anchor.",
            },
            // ───── Window-reset state ───────────────────────────────────
            RegistryEntry {
                name: "portfolio_state",
                category: ResetCategory::WindowReset,
                description: "Per-window portfolio (ps[0..8]) — reset at window start",
            },
            RegistryEntry {
                name: "hold_time",
                category: ResetCategory::WindowReset,
                description: "ps[5] / ps[10] — consecutive bars in position",
            },
            RegistryEntry {
                name: "entry_price",
                category: ResetCategory::WindowReset,
                description: "ps[3] — entry price of current trade",
            },
            // ───── Soft-reset state (anneals across folds) ──────────────
            RegistryEntry {
                name: "isv_grad_balance_targets",
                category: ResetCategory::SoftReset { decay_bars: 500 },
                description: "ISV[31..35) — per-branch grad-norm targets",
            },
            RegistryEntry {
                name: "isv_grad_scale_limit",
                category: ResetCategory::SoftReset { decay_bars: 500 },
                description: "ISV[35] — scale-clamp limit EMA",
            },
            // ───── Training-persist state ───────────────────────────────
            RegistryEntry {
                name: "network_params",
                category: ResetCategory::TrainingPersist,
                description: "Online network weights (all tensors)",
            },
            RegistryEntry {
                name: "target_network",
                category: ResetCategory::TrainingPersist,
                description: "Target network weights — Polyak EMA of online",
            },
            RegistryEntry {
                name: "adam_momentum",
                category: ResetCategory::TrainingPersist,
                description: "Adam optimizer first moment (m)",
            },
            RegistryEntry {
                name: "adam_variance",
                category: ResetCategory::TrainingPersist,
                description: "Adam optimizer second moment (v)",
            },
            RegistryEntry {
                name: "adam_step",
                category: ResetCategory::TrainingPersist,
                description: "Adam step counter t",
            },
            RegistryEntry {
                name: "replay_buffer",
                category: ResetCategory::TrainingPersist,
                description: "PER experience buffer — persists across folds",
            },
            // ───── Schema-contract state ────────────────────────────────
            RegistryEntry {
                name: "ISV_LAYOUT_FINGERPRINT",
                category: ResetCategory::SchemaContract,
                description: "ISV[55..57) — compile-time structural hash of slot layout; fail-fast only, no migration path",
            },
            RegistryEntry {
                name: "isv_iql_branch_scale_floor",
                category: ResetCategory::SchemaContract,
                description: "ISV[36] — IQL branch_scales floor (safety bound, bootstrap-only)",
            },
            RegistryEntry {
                name: "isv_total_epochs",
                category: ResetCategory::SchemaContract,
                description: "ISV[TOTAL_EPOCHS_INDEX=40] — total epoch count for this run; constant after construction",
            },
            RegistryEntry {
                name: "isv_cql_alpha",
                category: ResetCategory::FoldReset,
                description: "ISV[CQL_ALPHA_INDEX=48] — CQL pessimism base coefficient; producer upgraded SchemaContract → FoldReset by Plan 3 Task 9 C.5 (GPU `cql_alpha_seed_update` kernel ramps slot 48 toward `config.cql_alpha × (1 - seed_frac)`); cold-start config.cql_alpha reapplied at fold boundary",
            },
            RegistryEntry {
                name: "isv_plan_threshold",
                category: ResetCategory::FoldReset,
                description: "ISV[PLAN_THRESHOLD_INDEX=49] — plan-MLP activation threshold; producer upgraded to GPU plan_threshold_update kernel (Plan 3 B.4); cold-start 0.5 reapplied at fold boundary",
            },
            // ───── Fold-reset state (pre-allocated GPU-written slots) ───
            RegistryEntry {
                name: "isv_q_quantiles",
                category: ResetCategory::FoldReset,
                description: "ISV[50..58) — per-branch Q P5/P95 EMAs (Plan 2 C.1); reset to v_min/v_max bootstrap at fold boundary",
            },
            RegistryEntry {
                name: "isv_epoch_idx",
                category: ResetCategory::FoldReset,
                description: "ISV[EPOCH_IDX_INDEX=39] — current epoch index; CPU writes at epoch boundary (Plan 1 Task 13)",
            },
            RegistryEntry {
                name: "isv_epsilon_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[EPSILON_EFF_INDEX=41] — effective epsilon; GPU epsilon_update kernel fills (Plan 1 Task 14)",
            },
            RegistryEntry {
                name: "isv_tau_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[TAU_EFF_INDEX=42] — effective tau; GPU tau_update kernel fills (Plan 1 Task 13)",
            },
            RegistryEntry {
                name: "isv_gamma_dir_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[GAMMA_DIR_EFF_INDEX=43] — direction-branch gamma; GPU per_branch_gamma_update fills (Plan 2 Task 3 D.2)",
            },
            RegistryEntry {
                name: "isv_gamma_mag_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[GAMMA_MAG_EFF_INDEX=44] — magnitude-branch gamma; GPU per_branch_gamma_update fills (Plan 2 Task 3 D.2)",
            },
            RegistryEntry {
                name: "isv_gamma_ord_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[GAMMA_ORD_EFF_INDEX=45] — order-branch gamma; GPU per_branch_gamma_update fills (Plan 2 Task 3 D.2)",
            },
            RegistryEntry {
                name: "isv_gamma_urg_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[GAMMA_URG_EFF_INDEX=46] — urgency-branch gamma; GPU per_branch_gamma_update fills (Plan 2 Task 3 D.2)",
            },
            RegistryEntry {
                name: "isv_kelly_cap_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_CAP_EFF_INDEX=47] — effective Kelly cap; GPU kelly_cap_update kernel aggregates ps[14..18] across envs",
            },
            // ───── C.2 Reward-component attribution EMAs (Plan 3 Task 1) ───
            RegistryEntry {
                name: "isv_reward_component_emas",
                category: ResetCategory::FoldReset,
                description: "ISV[63..69) — per-component |reward| EMAs [popart,cf,trail,micro,opp_cost,bonus]; GPU reward_component_ema kernel fills (Plan 3 C.2)",
            },
            // ───── B.2 ISV-driven trade-attempt novelty bonus (Plan 3 Task 3) ─
            RegistryEntry {
                name: "isv_trade_attempt_rate_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[71] — Flat→Positioned transition rate EMA; GPU trade_rate_ema_update kernel fills (Plan 3 B.2)",
            },
            RegistryEntry {
                name: "isv_trade_target_rate",
                category: ResetCategory::FoldReset,
                description: "ISV[72] — reference rate for novelty, frozen at epoch 5 from measured EMA (Plan 3 B.2)",
            },
            // ───── B.4 Adaptive plan threshold readiness EMA (Plan 3 Task 4) ─
            RegistryEntry {
                name: "isv_readiness_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[75] — batch-mean readiness EMA; GPU plan_threshold_update kernel fills; drives PLAN_THRESHOLD_INDEX=49 derivation (Plan 3 B.4)",
            },
            // ───── C.3 Train-vs-val state-distribution KL (Plan 3 Task 7) ───
            RegistryEntry {
                name: "isv_state_kl_train_val_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[78] — train-vs-val moment-match KL EMA on OFI dims; GPU state_kl_moment_match kernel fills (Plan 3 C.3)",
            },
            RegistryEntry {
                name: "isv_state_kl_amplification",
                category: ResetCategory::FoldReset,
                description: "ISV[79] — Flat-trap escape amplifier ∈ [1, 2] driven by KL ratio; consumed by B.1 opp_cost + B.2 bonus (Plan 3 C.3)",
            },
            // ───── B.3 GPU-only seeded warm-start (Plan 3 Task 8) ───
            RegistryEntry {
                name: "isv_seed_steps_target",
                category: ResetCategory::SchemaContract,
                description: "ISV[SEED_STEPS_TARGET_INDEX=82] — config replay_seed_steps; constant for the run, written once at constructor (Plan 3 B.3)",
            },
            RegistryEntry {
                name: "isv_seed_steps_done",
                category: ResetCategory::FoldReset,
                description: "ISV[SEED_STEPS_DONE_INDEX=83] — cumulative seed-phase steps; GPU-incremented each collect_experiences (Plan 3 B.3)",
            },
            RegistryEntry {
                name: "isv_seed_frac_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[SEED_FRAC_EMA_INDEX=84] — seed-fraction EMA, Task 9 CQL ramp consumer; cold-start 1.0 (Plan 3 B.3)",
            },
            // ───── E.5 Attention-focus interpretability (Plan 4 Task 5 Mode A) ──
            RegistryEntry {
                name: "isv_vsn_mag_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MAG_EMA_INDEX=87] — magnitude-branch VSN-weight magnitude EMA; GPU attention_focus_ema_update kernel fills (Plan 4 E.5 Mode A)",
            },
            RegistryEntry {
                name: "isv_vsn_dir_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_DIR_EMA_INDEX=88] — direction-branch VSN-weight magnitude EMA; GPU attention_focus_ema_update kernel fills (Plan 4 E.5 Mode A)",
            },
            RegistryEntry {
                name: "isv_mamba2_retention_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[MAMBA2_RETENTION_EMA_INDEX=89] — Mamba2 state-transition magnitude EMA, retention proxy; GPU attention_focus_ema_update kernel fills (Plan 4 E.5 Mode A)",
            },
            // ───── Plan 4 Task 2c.3c.5: trunk-RMS EMA producer ─────────────
            RegistryEntry {
                name: "isv_h_s2_rms_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[H_S2_RMS_EMA_INDEX=96] — per-batch RMS(save_h_s2) EMA (α=0.05); GPU h_s2_rms_ema_update kernel fills; producer-only in 2c.3c.5, consumer wired in 2c.3c.6 (mag_concat_qdir adaptive-scale). SP4 Task A13.0 retrofit — Pearl A sentinel 0.0 reapplied at fold boundary (paired with sp4_wiener_state reset zeroing state.x_lag in lockstep so the new fold's first producer launch triggers Pearl A's first-observation replacement)",
            },
            // ───── Plan 4 Task 3 (E.3): IQN multi-quantile diagnostic EMAs ──
            RegistryEntry {
                name: "isv_iqn_q_p05_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[IQN_Q_P05_EMA_INDEX=99] — mean |Q| at IQN τ=0.05 EMA; GPU iqn_quantile_ema_update kernel fills (Plan 4 Task 3 E.3). Cold-start 0.0 reapplied at fold boundary. Diagnostic only — no consumer kernel reads slot 99 in this commit",
            },
            RegistryEntry {
                name: "isv_iqn_q_p25_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[IQN_Q_P25_EMA_INDEX=100] — mean |Q| at IQN τ=0.25 EMA; GPU iqn_quantile_ema_update kernel fills (Plan 4 Task 3 E.3). Cold-start 0.0 reapplied at fold boundary. Diagnostic only",
            },
            RegistryEntry {
                name: "isv_iqn_q_p75_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[IQN_Q_P75_EMA_INDEX=101] — mean |Q| at IQN τ=0.75 EMA; GPU iqn_quantile_ema_update kernel fills (Plan 4 Task 3 E.3). Cold-start 0.0 reapplied at fold boundary. Diagnostic only",
            },
            RegistryEntry {
                name: "isv_iqn_q_p95_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[IQN_Q_P95_EMA_INDEX=102] — mean |Q| at IQN τ=0.95 EMA; GPU iqn_quantile_ema_update kernel fills (Plan 4 Task 3 E.3). Cold-start 0.0 reapplied at fold boundary. Diagnostic only",
            },
            // ───── Plan 4 Task 1B-ii: VSN per-group mask EMAs ──────────
            RegistryEntry {
                name: "isv_vsn_mask_g0_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MASK_GROUP_0_EMA_INDEX=105] — `market` group importance mask EMA (α=0.05); GPU vsn_mask_ema_update kernel fills (Plan 4 Task 1B-i kernel; launch site wired in 1B-iii). SP4 Task A13.3 retrofit — Pearl A sentinel 0.0 reapplied at fold boundary (paired with sp4_wiener_state reset zeroing state.x_lag in lockstep so the new fold's first producer launch triggers Pearl A's first-observation replacement)",
            },
            RegistryEntry {
                name: "isv_vsn_mask_g1_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MASK_GROUP_1_EMA_INDEX=106] — `ofi` group importance mask EMA; same producer/contract as g0; SP4 Task A13.3 sentinel 0.0",
            },
            RegistryEntry {
                name: "isv_vsn_mask_g2_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MASK_GROUP_2_EMA_INDEX=107] — `tlob` group importance mask EMA; same producer/contract as g0; SP4 Task A13.3 sentinel 0.0",
            },
            RegistryEntry {
                name: "isv_vsn_mask_g3_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MASK_GROUP_3_EMA_INDEX=108] — `mtf` group importance mask EMA; same producer/contract as g0; SP4 Task A13.3 sentinel 0.0",
            },
            RegistryEntry {
                name: "isv_vsn_mask_g4_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MASK_GROUP_4_EMA_INDEX=109] — `portfolio` group importance mask EMA; same producer/contract as g0; SP4 Task A13.3 sentinel 0.0",
            },
            RegistryEntry {
                name: "isv_vsn_mask_g5_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VSN_MASK_GROUP_5_EMA_INDEX=110] — `plan_isv` group importance mask EMA; same producer/contract as g0; SP4 Task A13.3 sentinel 0.0",
            },
            // ───── Plan 4 Task 6 Commit A: aux-head loss EMAs ─────────
            RegistryEntry {
                name: "isv_aux_next_bar_mse_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_NEXT_BAR_MSE_EMA_INDEX=113] — next-bar regression head batch-mean MSE EMA (α=0.05); GPU aux_heads_loss_ema_update kernel fills (Plan 4 Task 6 Commit A; producer kernel landed in Commit A, launch site wires in Commit B alongside launch_h_s2_rms_ema). Cold-start 0.0 (no aux forwards have happened yet) reapplied at fold boundary. Diagnostic only — no GPU consumer kernel reads slot 113 in either commit",
            },
            RegistryEntry {
                name: "isv_aux_regime_ce_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_REGIME_CE_EMA_INDEX=114] — regime classification head batch-mean cross-entropy EMA; same producer/contract as next_bar_mse_ema; cold-start 0.0",
            },
            // SP13 B1.0 (2026-05-05): the former
            // `isv_aux_label_scale_ema` registry entry (FoldReset for ISV
            // slot 117) was retired together with the slot itself when
            // the next-bar MSE flipped to scale-free. No replacement
            // entry is needed — the slot is no longer written by any
            // producer, so there is nothing to reset at fold boundary.
            // Mixture-of-Experts per-expert utilization (slots 118..126).
            // SP4 Task A13.2 retrofit — Pearl A sentinel 0.0 at fold boundary.
            RegistryEntry {
                name: "isv_moe_expert_util_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[MOE_EXPERT_UTIL_EMA_BASE..MOE_EXPERT_UTIL_EMA_BASE+8) — per-expert gate-weight EMA (α=0.05); GPU moe_expert_util_ema_update kernel fills (Phase 2 task 2.4); SP4 Task A13.2 retrofit — Pearl A sentinel 0.0 reapplied at fold boundary (paired with sp4_wiener_state reset)",
            },
            // MoE gate-distribution entropy EMA (slot 126).
            // SP4 Task A13.2 retrofit — Pearl A sentinel 0.0 at fold boundary.
            RegistryEntry {
                name: "isv_moe_gate_entropy_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[MOE_GATE_ENTROPY_EMA_INDEX=126] — entropy of batch-mean gate distribution, EMA α=0.05; SP4 Task A13.2 retrofit — Pearl A sentinel 0.0 reapplied at fold boundary (paired with sp4_wiener_state reset); GPU moe_gate_entropy_ema_update kernel fills (Phase 2 task 2.4)",
            },
            // MoE adaptive load-balance λ controller (slot 128).
            // Reset to moe_lambda_floor (= old static 0.01 default) at fold
            // boundary so the new fold starts from the permanent minimum
            // and rises adaptively as the entropy EMA decays under it.
            // Per `pearl_blend_formulas_must_have_permanent_floor.md`, the
            // floor is a permanent minimum — λ_eff never drops below it.
            RegistryEntry {
                name: "isv_moe_lambda_eff",
                category: ResetCategory::FoldReset,
                description: "ISV[MOE_LAMBDA_EFF_INDEX=128] — adaptive load-balance λ from `moe_lambda_eff_update` controller; reset to config.moe_lambda_floor at fold boundary (gate uniform-init ⇒ deficit=0 ⇒ λ_floor); per-step kernel raises λ_eff up to (floor + max_extra) when gate-entropy EMA decays below entropy_target_frac × ln(K)",
            },
            // Plan C Phase 2 follow-up A.2 (2026-04-29): adaptive Polyak-tau
            // drift signal (slot 129). Reset to 0.0 at fold boundary so the
            // new fold starts with no inherited drift dampening — the first
            // epoch's tau passes through unchanged (drift_factor = 1) and
            // the producer kernel `q_drift_rate_ema_update` only re-fires
            // once `DQNTrainer::prev_epoch_q_mean` has graduated above 1e-6
            // (gated in `training_loop.rs`). Companion to A.1's
            // prev_epoch_q_mean reset in `reset_for_fold` — both ensure
            // cross-fold drift state cannot leak into the new fold's
            // tau-dampening computation.
            RegistryEntry {
                name: "isv_q_drift_rate",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_DRIFT_RATE_INDEX=129] — adaptive Polyak-tau drift signal ∈ [0, 4]; GPU q_drift_rate_ema_update kernel fills (Plan C A.2). Cold-start 0.0 (no-op dampening factor) reapplied at fold boundary; consumer tau_update_kernel.cu multiplies tau_eff by 1/(1+ISV[129]) so dampening is monotone — tau only ever decreases under drift, healthy runs unaffected",
            },
            // Plan C Phase 2 follow-up K (2026-04-29): adaptive fold-boundary
            // warmup signal (slot 130). Reset to 0.0 at fold boundary so the
            // new fold's first steps see heavy lr/clip damping; the kernel
            // raises the factor toward 1.0 as the fast grad-norm EMA catches
            // up to the slow steady-state EMA (which persists across folds).
            // Companion to A.1+A.2+A.3 fold-boundary state-reset family.
            // Per `pearl_blend_formulas_must_have_permanent_floor.md`, the
            // damping floor (lr_floor=0.05, clip_floor=0.1) is a permanent
            // minimum — even at factor=0 the consumers never reach zero lr/clip.
            RegistryEntry {
                name: "isv_fold_warmup_factor",
                category: ResetCategory::FoldReset,
                description: "ISV[FOLD_WARMUP_FACTOR_INDEX=130] — adaptive fold-boundary warmup factor ∈ [0, 1]; GPU fold_warmup_factor_update kernel fills (Plan C K). Cold-start 0.0 (heavy damping at fold start) reapplied at fold boundary; consumers in training_loop.rs derive lr_eff = lr_base × max(0.05, factor) and clip_eff = clip_base × (0.1 + 0.9 × factor) — both monotone (only dampen). Companion FoldReset entry `isv_grad_norm_fast_ema` resets the kernel's numerator EMA so the ratio starts at 0",
            },
            // Plan C Phase 2 follow-up K (2026-04-29): fast grad-norm EMA
            // mapped-pinned scalar feeding `fold_warmup_factor_update`'s
            // numerator. Companion to `isv_fold_warmup_factor` — both must
            // reset together so the ratio (fast/slow) starts at 0 → factor=0
            // → heavy damping. The slow EMA does NOT reset (cross-fold
            // steady-state baseline). Per `feedback_no_partial_refactor.md`,
            // both halves of the warmup-factor input contract are reset in
            // lockstep.
            RegistryEntry {
                name: "isv_grad_norm_fast_ema",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.grad_norm_fast_ema_pinned — fast (α=0.1, ~10-step horizon) EMA of `gr.raw_grad_norm`, host-side mapped-pinned scalar updated GPU-side by `update_grad_norm_emas_kernel` (chained on the producer's stream after `launch_grad_norm_finalize`) and consumed by `fold_warmup_factor_update` (Plan C K). SP4 Layer C close-out C1 redesigned (2026-05-01) migrated the prior host-side EMA arithmetic block in `update_adaptive_clip` to GPU per `feedback_no_cpu_compute_strict`. Reset to 0.0 at fold boundary so the warmup-factor ratio starts at 0 → consumer-derived lr_eff/clip_eff start at their permanent-floor values; recovers to slow-EMA baseline as gradients stabilise. Slow EMA companion (grad_norm_slow_ema_pinned) deliberately persists across folds — it tracks the cross-fold steady-state grad scale that the warmup factor compares against.",
            },
            // ───── SP4 Layer A Task A12 (2026-04-30): adaptive bound +
            // Wiener-state + Pearl C engagement-counter fold-boundary resets.
            //
            // Pearl A's first-observation replacement requires both
            // `prev_x_mean` (the ISV bound slot) AND `state.x_lag` (Wiener
            // triple offset 2) to be exactly 0 when a producer first fires
            // in a new fold. Without resetting them at the fold boundary
            // the new fold's first producer launch wouldn't see the sentinel
            // and would EMA the new step-observation against a stale fold-N
            // estimate — exactly the cross-fold anchor staleness Mech 8's
            // reverted slow_ema reset was trying to fix imperfectly.
            //
            // Pearl C's engagement-rate Wiener-EMA is per-(group, block);
            // its 2816 i32 counters likewise must zero at fold boundary so
            // post-clamp saturation detection starts each fold from a clean
            // baseline. Per `feedback_no_partial_refactor.md` — every half
            // of the SP4 fold-reset contract (40 bound slots + 207-float
            // Wiener triples + 2816-int engagement counters) migrates in
            // the same commit.
            //
            // Each entry below is one logical group; the reset dispatch arm
            // in `reset_named_state` writes 0.0 to every slot in the group.
            // ──────────────────────────────────────────────────────────────
            RegistryEntry {
                name: "sp4_target_q_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[TARGET_Q_BOUND_INDEX=131] — Mech 1 target_q clamp bound; SP4 Pearl A sentinel 0 at fold boundary so the new fold's first `target_q_p99_update` launch fires the first-observation replacement (Task A12)",
            },
            RegistryEntry {
                name: "sp4_atom_pos_bounds",
                category: ResetCategory::FoldReset,
                description: "ISV[ATOM_POS_BOUND_BASE..+SP4_BRANCH_COUNT) = ISV[132..136) — Mech 2 atom-position clamp bounds per branch; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_weight_bounds",
                category: ResetCategory::FoldReset,
                description: "ISV[WEIGHT_BOUND_BASE..+SP4_PARAM_GROUP_COUNT) = ISV[136..144) — Mech 9 post-Adam weight clamp bounds per param group; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_adam_m_bounds",
                category: ResetCategory::FoldReset,
                description: "ISV[ADAM_M_BOUND_BASE..+SP4_PARAM_GROUP_COUNT) = ISV[144..152) — Mech 5 Adam momentum diagnostic per param group; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_adam_v_bounds",
                category: ResetCategory::FoldReset,
                description: "ISV[ADAM_V_BOUND_BASE..+SP4_PARAM_GROUP_COUNT) = ISV[152..160) — Mech 5 Adam variance diagnostic per param group; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_wd_rate_bounds",
                category: ResetCategory::FoldReset,
                description: "ISV[WD_RATE_BASE..+SP4_PARAM_GROUP_COUNT) = ISV[160..168) — AdamW weight_decay rate per param group; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_grad_clip_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[GRAD_CLIP_BOUND_INDEX=168] — Mech 6 adaptive_clip upper bound; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_h_s2_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[H_S2_BOUND_INDEX=169] — Mech 10 h_s2 clamp bound; SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_l1_lambda_trunk",
                category: ResetCategory::FoldReset,
                description: "ISV[L1_LAMBDA_TRUNK_INDEX=170] — trunk L1 lambda (group-0-only); SP4 Pearl A sentinel 0 at fold boundary (Task A12)",
            },
            RegistryEntry {
                name: "sp4_bw_d_h_s2_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[BW_D_H_S2_BOUND_INDEX=171] — Layer C #260 backward-grad sanitiser bound for `bw_d_h_s2`. SP4 Pearl A sentinel 0 at fold boundary so the new fold's first `launch_sp4_bw_d_h_s2_p99` observation replaces directly (no stale prev_x_mean). Companion to sp4_wiener_state's slot-69 triple (offset 120..123) — both halves reset together per `feedback_no_partial_refactor.md`",
            },
            RegistryEntry {
                name: "sp4_q_dir_grad_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_DIR_GRAD_BOUND_INDEX=172] — Layer C #260 backward-grad sanitiser bound for `d_value_logits ∪ d_adv_logits` (multi-sub-buffer p99). SP4 Pearl A sentinel 0 at fold boundary so the new fold's first `launch_sp4_q_dir_grad_p99` observation replaces directly. Companion to sp4_wiener_state's slot-70 triple (offset 123..126) — both halves reset together per `feedback_no_partial_refactor.md`",
            },
            RegistryEntry {
                name: "sp4_wiener_state",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.wiener_state_buf [(71 + SP5_PRODUCER_COUNT) × 3 floats; total = (SP4 + SP5/SP6/SP7/SP8/SP9/SP10/SP11 producers) × {sample_var, diff_var, x_lag}] — SP4 Pearl D Wiener-EMA state for SP4 block [0..213) (40 SP4 + 29 Task-A13 retrofit + 2 Layer-C-#260 producers). Mapped-pinned f32; bulk write_bytes(0) at fold boundary covers the full buffer [0..(71 + SP5_PRODUCER_COUNT) × 3) so Pearl A's sentinel branch fires on the new fold's first producer launch for ALL SP4 and SP5+ producers (`prev_x_mean == 0 AND state.x_lag == 0` → first-observation replacement). Companion to the 11 SP4 ISV bound entries above — both halves of the sentinel contract reset together per `feedback_no_partial_refactor.md`. Buffer size derives from SP5_PRODUCER_COUNT (formula form, not a hardcoded literal) to avoid drift on each subsequent SP.",
            },
            RegistryEntry {
                name: "sp4_clamp_engage_counters",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.clamp_engage_per_block_buf [2816 ints = (SP4_PARAM_GROUP_COUNT + 3 curiosity sub-launches) × MAX_BLOCKS_PER_ADAM = 11 × 256] — SP4 Pearl C engagement counter (per-(group, Adam-launch-block) clamp-trigger count). Mapped-pinned i32; bulk write_bytes(0) at fold boundary so the new fold's engagement-rate tracking restarts from a clean 0 baseline. Buffer length grew 2048→2816 in Task A14/A15 to give Curiosity's 4 sub-launches (W1/b1/W2/b2) distinct offset slots avoiding per-block index collisions (Task A12 + A14/A15)",
            },
            RegistryEntry {
                name: "sp4_pearl_c_rate_deficit_state",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.pearl_c_rate_deficit_state_buf [24 floats = SP4_PARAM_GROUP_COUNT × {sample_var, diff_var, x_lag}] — SP4 Pearl C rate-deficit Wiener-state (per param group). Mapped-pinned f32; bulk write_bytes(0) at fold boundary so the new fold's engagement-rate-deficit EMA restarts from Pearl A sentinel (`prev_x_mean == 0 AND state.x_lag == 0` → first-observation replacement). Paired with sp4_pearl_c_rate_deficit_ema — both reset together (Task A15)",
            },
            RegistryEntry {
                name: "sp4_pearl_c_rate_deficit_ema",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.pearl_c_rate_deficit_ema [8 floats, host-only [f32; SP4_PARAM_GROUP_COUNT]] — SP4 Pearl C rate-deficit EMA per param group (the `prev_x_mean` surrogate read by `pearls_ad_update`). Reset to all-zeros at fold boundary so the new fold's deficit tracking restarts from the Pearl A sentinel. Companion to sp4_pearl_c_rate_deficit_state (Task A15)",
            },
            // ───── SP5 Task A1: Pearl 1 atom-span + shared-signal ISV entries ──
            RegistryEntry {
                name: "sp5_atom_v_center",
                category: ResetCategory::FoldReset,
                description: "ISV[ATOM_V_CENTER_BASE=174..178) — per-branch C51 atom-span center (v_center). SP5 Pearl A sentinel 0 at fold boundary so the new fold's first `pearl_1_atom_update` launch fires the first-observation replacement (Task A1).",
            },
            RegistryEntry {
                name: "sp5_atom_v_half",
                category: ResetCategory::FoldReset,
                description: "ISV[ATOM_V_HALF_BASE=178..182) — per-branch C51 atom half-span (v_half = max_abs_dev × headroom). SP5 Pearl A sentinel 0 at fold boundary (Task A1).",
            },
            RegistryEntry {
                name: "sp5_atom_headroom",
                category: ResetCategory::FoldReset,
                description: "ISV[ATOM_HEADROOM_BASE=182..186) — per-branch C51 atom headroom multiplier (init 6.0 via Pearl A bootstrap). SP5 Pearl A sentinel 0 at fold boundary so the headroom controller re-bootstraps to 6.0 at the new fold's first step (Task A1).",
            },
            RegistryEntry {
                name: "sp5_atom_clip_rate",
                category: ResetCategory::FoldReset,
                description: "ISV[ATOM_CLIP_RATE_BASE=186..190) — per-branch atom clip rate (atoms_clip_count / (batch_size*13)). SP5 Pearl A sentinel 0 at fold boundary (Task A1).",
            },
            RegistryEntry {
                name: "sp5_budget_c51",
                category: ResetCategory::FoldReset,
                description: "ISV[BUDGET_C51_BASE=190..194) — per-branch C51 loss budget share. SP7 (2026-05-03): will be driven by the loss-balance controller using flatness-modulated target ratio (C51/IQN ≤ 1.0×flatness). Pearl A sentinel 0 at fold boundary; consumer-side floor currently 0.05 (`fused_training.rs:3384`). (Pearl 2 will stop writing this slot in SP7 T6; T7 replaces the consumer floor with sentinel-aware bootstrap.)",
            },
            RegistryEntry {
                name: "sp5_budget_iqn",
                category: ResetCategory::FoldReset,
                description: "ISV[BUDGET_IQN_BASE=194..198) — per-branch IQN loss budget share (BASE_IQN + (1-flatness)×(1-BASE_IQN), dominates when Q is flat relative to noise σ). SP5 Pearl A sentinel 0 at fold boundary (Task A3).",
            },
            RegistryEntry {
                name: "sp5_budget_cql",
                category: ResetCategory::FoldReset,
                description: "ISV[BUDGET_CQL_BASE=198..202) — per-branch CQL loss budget share. SP7 (2026-05-03): will be driven by the loss-balance controller (`loss_balance_controller_kernel`) using flatness-modulated target ratio (CQL/IQN ≤ 2.0×(1−flatness)). Pearl A sentinel 0 at fold boundary; consumer-side floor currently 0.02 (`fused_training.rs:3386`). (Pearl 2 will stop writing this slot in SP7 T6; T7 replaces the consumer floor with sentinel-aware bootstrap.)",
            },
            RegistryEntry {
                name: "sp5_budget_ens",
                category: ResetCategory::FoldReset,
                description: "ISV[BUDGET_ENS_BASE=202..206) — per-branch ensemble loss budget share. SP7 (2026-05-03): consumer-side floor currently 0.02 (`fused_training.rs:3387`); Ens is currently not actively driven (no loss-balance target ratio defined for Ens vs IQN). Pearl A sentinel 0 at fold boundary. (Pearl 2 will stop writing this slot in SP7 T6; T7 replaces the consumer floor with sentinel-aware bootstrap.)",
            },
            RegistryEntry {
                name: "sp5_flatness",
                category: ResetCategory::FoldReset,
                description: "ISV[FLATNESS_BASE=206..210) — per-branch flatness signal (var(Q[b]) / (σ[b]² + EPS_DIV), clamped to [0, 1]). Drives Pearl 2's per-branch IQN/C51 split. SP5 Pearl A sentinel 0 at fold boundary (Task A3).",
            },
            RegistryEntry {
                name: "sp5_noisy_sigma",
                category: ResetCategory::FoldReset,
                description: "ISV[NOISY_SIGMA_BASE=210..214) — per-branch NoisyNet sigma (= sigma_fraction x v_half from Pearl 1). SP5 Pearl A sentinel 0 at fold boundary so the new fold's first pearl_3_sigma_update launch fires the first-observation replacement (Task A2).",
            },
            RegistryEntry {
                name: "sp5_sigma_fraction",
                category: ResetCategory::FoldReset,
                description: "ISV[SIGMA_FRACTION_BASE=214..218) — per-branch sigma fraction (entropy-deficit controller, init 0.1 via Pearl A bootstrap, envelope [0.001, 0.5]). SP5 Pearl A sentinel 0 at fold boundary so the controller re-bootstraps to 0.1 at the new fold's first step (Task A2).",
            },
            RegistryEntry {
                name: "sp5_branch_entropy",
                category: ResetCategory::FoldReset,
                description: "ISV[BRANCH_ENTROPY_BASE=218..222) — per-branch action entropy (mean over batch, from q_branch_stats softmax). SP5 Pearl A sentinel 0 at fold boundary (Task A1).",
            },
            RegistryEntry {
                name: "sp5_q_var_per_branch",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_VAR_PER_BRANCH_BASE=222..226) — per-branch Q-value variance (mean over batch×branch-actions). SP5 Pearl A sentinel 0 at fold boundary (Task A1).",
            },
            // SP7 (2026-05-03): loss-balance controller per-branch
            // Wiener-state EMAs. Both halves of the Pearl A contract
            // (sentinel 0 at fold boundary so the controller's
            // `old_budget < EPS_DIV` cold-start branch fires).
            RegistryEntry {
                name: "sp7_lb_diff_var_cql",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_DIFF_VAR_CQL_BASE=297..301) — per-branch EMA of (candidate_cql − old_cql)² used as Wiener α numerator for the CQL budget controller. SP7 Pearl A sentinel 0 at fold boundary so α resets cleanly when budgets re-bootstrap.",
            },
            RegistryEntry {
                name: "sp7_lb_sample_var_cql",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_SAMPLE_VAR_CQL_BASE=301..305) — per-branch EMA of (cql_norm)² used as Wiener α denominator for the CQL budget controller. SP7 Pearl A sentinel 0 at fold boundary.",
            },
            RegistryEntry {
                name: "sp7_lb_diff_var_c51",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_DIFF_VAR_C51_BASE=305..309) — per-branch EMA of (candidate_c51 − old_c51)² used as Wiener α numerator for the C51 budget controller. SP7 Pearl A sentinel 0 at fold boundary.",
            },
            RegistryEntry {
                name: "sp7_lb_sample_var_c51",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_SAMPLE_VAR_C51_BASE=309..313) — per-branch EMA of (c51_norm)² used as Wiener α denominator for the C51 budget controller. SP7 Pearl A sentinel 0 at fold boundary.",
            },
            // SP7 activation-flag fix (2026-05-03): per-(head, branch)
            // activation flags. Monotonic per fold (kernel writes 1.0 once,
            // never 0; apply_pearls_ad short-circuits 0 writes). FoldReset
            // to 0 forces the new fold to re-activate from scratch as
            // gradients populate, so the consumer's bootstrap covers the
            // fold's first few steps and the controller's first real
            // budget update lands without the indistinguishable-state
            // pathology that existed pre-fix (kernel cold_start_basis
            // numerically equaled consumer's bootstrap).
            RegistryEntry {
                name: "sp7_lb_cql_active",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_CQL_ACTIVE_BASE=313..317) — SP7 controller activation flag for CQL — fold-boundary reset to 0 forces fresh activation as grads populate in the new fold.",
            },
            RegistryEntry {
                name: "sp7_lb_c51_active",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_C51_ACTIVE_BASE=317..321) — SP7 controller activation flag for C51 — fold-boundary reset to 0 forces fresh activation as grads populate in the new fold.",
            },
            // SP8 (Fix 36, 2026-05-03): ISV-driven adaptive MAX_BUDGET cap.
            // Replaces the hardcoded `MAX_BUDGET=1.0f` constant in
            // `loss_balance_controller_kernel.cu` per
            // `pearl_controller_anchors_isv_driven.md` and
            // `feedback_isv_for_adaptive_bounds.md`. Three FoldReset entries
            // (canary + per-head cap blocks) — sentinel 0 at fold boundary
            // so Pearl A's first-observation replacement fires on the new
            // fold's first producer launch. Wiener-state companion is reset
            // by the existing bulk memset of `wiener_state_buf` covered by
            // the `sp4_wiener_state` registry entry's dispatch arm
            // (SP5_PRODUCER_COUNT linear span grew 147 → 156, the buffer
            // expanded in lockstep).
            RegistryEntry {
                name: "sp8_train_active_frac",
                category: ResetCategory::FoldReset,
                description: "ISV[TRAIN_ACTIVE_FRAC_INDEX=321] — SP8 Fix 36 canary signal. EMA-smoothed per-step train-rollout active fraction `(Short + Long) / total`, produced by `train_active_frac_compute_kernel` from `monitoring_summary[5..17)`. Drives `loss_balance_max_budget_compute_kernel` (the adaptive cap). FoldReset sentinel 0 at fold boundary so Pearl A's first-observation replacement fires on the new fold's first producer launch (per `pearl_first_observation_bootstrap.md`). Replaces the host-side compute previously at `training_loop.rs:3392-3396` per `feedback_no_cpu_compute_strict.md`.",
            },
            RegistryEntry {
                name: "sp8_lb_max_budget_cql",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_MAX_BUDGET_CQL_BASE=322..326) — SP8 Fix 36 per-branch CQL MAX_BUDGET cap. Produced by `loss_balance_max_budget_compute_kernel` from the train_active_frac canary via linear interpolation `FLOOR + active_frac × (CEIL − FLOOR)` (FLOOR=0.01, CEIL=1.0). Read by `loss_balance_controller_kernel` to clamp the per-branch CQL budget — replaces the prior hardcoded `MAX_BUDGET=1.0f` regime-encoded constant. FoldReset sentinel 0 at fold boundary; Pearl A bootstraps the cap from the producer's first observation.",
            },
            RegistryEntry {
                name: "sp8_lb_max_budget_c51",
                category: ResetCategory::FoldReset,
                description: "ISV[LB_MAX_BUDGET_C51_BASE=326..330) — SP8 Fix 36 per-branch C51 MAX_BUDGET cap. Produced by `loss_balance_max_budget_compute_kernel` (same producer as the CQL block) from the same `train_active_frac` canary; per-(head, branch) layout is forward-compatible with future divergent caps. Read by `loss_balance_controller_kernel` to clamp the per-branch C51 budget. FoldReset sentinel 0 at fold boundary.",
            },
            // SP9 (Fix 37, 2026-05-03): Kelly cold-start warmup floor —
            // fully ISV-driven. Replaces the prior implicit cold-start
            // exit (single-axis statistical via `total_trades >= 10`) with
            // OR'd statistical / behavioral / temporal confidence per
            // `pearl_cold_start_exit_signal_or.md`. Co-located eval_dist
            // GPU migration deletes the DtoH host helper per
            // `feedback_no_cpu_compute_strict.md`. Nine FoldReset entries
            // (warmup_floor + q_var_mag_ema + divergence + 3 EMA targets +
            // 3 eval_dist mag bins) — sentinel 0 at fold boundary so
            // Pearl A's first-observation replacement fires on the new
            // fold's first producer launch. Wiener-state companion is
            // reset by the existing bulk memset of `wiener_state_buf`
            // covered by the `sp4_wiener_state` registry entry's dispatch
            // arm (SP5_PRODUCER_COUNT linear span grew 156 → 165, the
            // buffer expanded in lockstep).
            RegistryEntry {
                name: "sp9_kelly_warmup_floor",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_WARMUP_FLOOR_INDEX=330] — SP9 Fix 37 adaptive Kelly cold-start floor. Produced by `kelly_warmup_floor_compute_kernel` from base_floor (q_var_mag self-relative ratio) × (1 − OR'd statistical/behavioral/temporal confidence). Consumed in `unified_env_step_core` (`trade_physics.cuh`) as an additional max-floor on `health_safety_sp5`. FoldReset sentinel 0 at fold boundary so the cap re-engages for new-fold learning until OR'd confidence accumulates. Per `pearl_cold_start_exit_signal_or.md`.",
            },
            RegistryEntry {
                name: "sp9_q_var_mag_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_VAR_MAG_EMA_INDEX=331] — SP9 Fix 37 EMA-tracked baseline of magnitude-branch Q-variance (`ISV[FLATNESS_BASE+1]`). Drives the self-relative `base_floor` ratio in the warmup-floor formula per `pearl_controller_anchors_isv_driven.md` (eliminates the prior 0.5 hardcoded half-Kelly constant). Produced by `q_var_mag_ema_compute_kernel`; smoothed by Pearl D Wiener-α; FoldReset sentinel 0 → Pearl A bootstraps from the new fold's first observation.",
            },
            RegistryEntry {
                name: "sp9_intent_eval_divergence",
                category: ResetCategory::FoldReset,
                description: "ISV[INTENT_EVAL_DIVERGENCE_INDEX=332] — SP9 Fix 37 intent vs eval Full-magnitude divergence ratio `intent_f / eval_f`. Behavioral-axis numerator of the OR'd cold-start exit. Produced by `intent_eval_divergence_compute_kernel` from `monitoring_summary[5..17)` + `ISV[EVAL_DIST_F_INDEX]`. Under healthy training the ratio ≈ 1; under val-Flat-collapse it rises sharply, dropping behavioral_conf to 0 and keeping the cap closed. FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first observation.",
            },
            RegistryEntry {
                name: "sp9_kelly_sample_count_target",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_SAMPLE_COUNT_TARGET_INDEX=333] — SP9 Fix 37.1 (2026-05-03) Invariant-1 numerical anchor: minimum trade samples (100.0) for statistical-confidence release of the OR'd cold-start exit. Originally Fix 37 routed this through `kelly_sample_count_target_ema_kernel` + Pearl A/D smoothing, but smoke-test-wrwkz revealed sentinel-bootstrap saturated the EMA to the first observation in epoch 1, making `current/target = 1.0` and defeating the cold-start floor. Now constructor-written ONCE per `feedback_isv_for_adaptive_bounds.md`. FoldReset rewrites the same Invariant-1 anchor (NOT sentinel 0) since this is a constant, not a stateful EMA. The consumer's `kelly_sample_count / sample_count_target` ratio yields a self-normalised `statistical_conf` in [0, 1] that rises monotonically as samples accumulate.",
            },
            RegistryEntry {
                name: "sp9_kelly_divergence_target",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_DIVERGENCE_TARGET_INDEX=334] — SP9 Fix 37.1 (2026-05-03) Invariant-1 numerical anchor: divergence ratio (2.0) above which intent-vs-eval is considered diverged enough to keep the cap closed (behavioral-axis denominator of the OR'd cold-start exit). Originally Fix 37 routed this through `kelly_divergence_target_ema_kernel` + Pearl A/D smoothing, but smoke-test-wrwkz revealed sentinel-bootstrap saturated the EMA to the first observation in epoch 1 (`div_tgt=70 005`), making the consumer's ratio collapse to 1.0 and defeating the cold-start floor. Now constructor-written ONCE per `feedback_isv_for_adaptive_bounds.md`. FoldReset rewrites the same Invariant-1 anchor (NOT sentinel 0). The consumer's `1 − divergence / divergence_target` ratio yields a self-normalised `behavioral_conf` in [0, 1] that drops sharply when divergence exceeds the threshold.",
            },
            RegistryEntry {
                name: "sp9_kelly_temporal_target",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_TEMPORAL_TARGET_INDEX=335] — SP9 Fix 37.1 (2026-05-03) Invariant-1 numerical anchor: minimum epochs in fold (5.0) before temporal-confidence release of the OR'd cold-start exit (the safety net per Risk 3 in the SP9 spec — always fires once epoch_idx ≥ target if statistical and behavioral both stay dormant). Originally Fix 37 routed this through `kelly_temporal_target_ema_kernel` + Pearl A/D smoothing, but smoke-test-wrwkz revealed sentinel-bootstrap saturated the EMA to the first observation in epoch 1 (`temp_tgt=1.0`), making temporal_conf trivially `epoch_idx/1.0 ≥ 1` from epoch 1 onwards. Now constructor-written ONCE per `feedback_isv_for_adaptive_bounds.md`. FoldReset rewrites the same Invariant-1 anchor (NOT sentinel 0). The consumer's `epoch_idx_in_fold / temporal_target` ratio yields a self-normalised `temporal_conf` in [0, 1] that rises linearly with fold-time.",
            },
            RegistryEntry {
                name: "sp9_eval_dist_q",
                category: ResetCategory::FoldReset,
                description: "ISV[EVAL_DIST_Q_INDEX=336] — SP9 Fix 37 GPU-resident eval-side Quarter mag fraction. Produced by `eval_intent_dist_compute_kernel` reading `intent_mag_buf` directly on the GPU; smoothed by Pearl D Wiener-α. Replaces the prior DtoH `read_eval_intent_magnitude_distribution()[0]` per `feedback_no_cpu_compute_strict.md`. FoldReset sentinel 0; Pearl A bootstraps from the first val window of the new fold.",
            },
            RegistryEntry {
                name: "sp9_eval_dist_h",
                category: ResetCategory::FoldReset,
                description: "ISV[EVAL_DIST_H_INDEX=337] — SP9 Fix 37 GPU-resident eval-side Half mag fraction. Same producer as Q/F. FoldReset sentinel 0.",
            },
            RegistryEntry {
                name: "sp9_eval_dist_f",
                category: ResetCategory::FoldReset,
                description: "ISV[EVAL_DIST_F_INDEX=338] — SP9 Fix 37 GPU-resident eval-side Full mag fraction. Same producer as Q/H. ALSO read by the `intent_eval_divergence_compute_kernel` each training step (cross-window persistent within a fold). FoldReset sentinel 0; Pearl A bootstraps from the first val window's first non-empty intent_mag_buf reduction.",
            },
            // SP10 (Fix 38, 2026-05-03): eval Thompson selector temperature.
            // Per `pearl_thompson_for_distributional_action_selection.md`
            // (amended) + `pearl_controller_anchors_isv_driven.md` +
            // `pearl_blend_formulas_must_have_permanent_floor.md`: the
            // rollout selector is unconditional Thompson; argmax is
            // reserved for the Bellman target. The temperature is a side-
            // output of `intent_eval_divergence_compute_kernel` clamped to
            // [0.5, 2.0]. FoldReset sentinel 0 so Pearl A's first-
            // observation replacement fires on the new fold's first
            // producer launch — the consumer's defensive
            // `if (!(temp > 0.5f)) temp = 0.5f` pre-bootstrap clamp keeps
            // the selector at its permanent-stochasticity floor before the
            // producer fires (read-after-reset in the same fold step).
            RegistryEntry {
                name: "sp10_eval_thompson_temp",
                category: ResetCategory::FoldReset,
                description: "ISV[EVAL_THOMPSON_TEMP_INDEX=339] — SP10 Fix 38 eval Thompson selector temperature. Produced as a side-output of `intent_eval_divergence_compute_kernel` (`temp = clamp(divergence/divergence_target, 0.5, 2.0)`). Consumed in `experience_action_select` direction-branch unconditionally (training AND eval) for the temperature-blended Thompson sample `q_eff[d] = E[Q][d] + temp · (q_sample[d] − E[Q][d])`. MIN_TEMP=0.5 enforces permanent stochasticity per `pearl_blend_formulas_must_have_permanent_floor.md`. Eliminates the val-Flat-collapse pathology (T10 train-multi-seed-khr7c on `8a25b330f`: dir_entropy=0, trade_count=1 in 214k bars) caused by the prior `eval_mode ⇒ argmax(E[Q])` selector branch. FoldReset sentinel 0; Pearl A bootstraps from the first observation; the consumer's defensive clamp keeps the selector at MIN_TEMP between fold-reset and first producer launch.",
            },
            // ── SP11 (Fix 39, 2026-05-04): reward-subsystem controller ─────
            //
            // Per `pearl_reward_as_controlled_subsystem.md` +
            // `pearl_controller_anchors_isv_driven.md`: 20 new ISV slots at
            // [340..360) populated by the SP11 controller chain — 6 component
            // weights + 4 controller scalar outputs + 10 canaries (val-sharpe
            // delta/var, 6 mag-ratios, saboteur engagement, PnL EMA). All
            // slots are FoldReset sentinel 0; Pearl A bootstraps from the
            // first producer launch on the new fold (per
            // `pearl_first_observation_bootstrap.md`). Producers and
            // consumers are introduced in subsequent A1/A2/B tasks; A0 is
            // additive — no consumer reads any of these slots yet, so the
            // trainer continues to behave identically.
            //
            // The 20 entries below mirror the registry layout established by
            // the SP9/SP10 entries above (one entry per uniquely-zeroed slot
            // / per-related-block). The 6 mag-ratio canaries occupy a
            // contiguous 6-slot block at [352..358) and share a single
            // entry — the dispatch arm zeroes the whole range with one loop,
            // matching the `sp5_pnl_aggregation`/`sp5_health_composition`
            // pattern.
            //
            // Wiener-state companion: the bulk memset of `wiener_state_buf`
            // covered by the `sp4_wiener_state` registry entry's dispatch
            // arm includes the new SP11 triples (the buffer linear span
            // grew from `(SP4_PRODUCER_COUNT + 166) × 3` to
            // `(SP4_PRODUCER_COUNT + 186) × 3` = +60 floats). Both halves
            // of the Pearl A sentinel contract reset together per
            // `feedback_no_partial_refactor.md`.
            //
            // SP11 Task A2 (2026-05-04): novelty visit-count hash table
            // reset arm — closes the A0 deferral. The buffer is a 1M-slot
            // f32 mapped-pinned table on `GpuDqnTrainer.novelty_hash_buf`;
            // the dispatch arm (`reset_named_state` in `training_loop.rs`)
            // zero-fills the host-side mapped slice via
            // `host_slice_mut().fill(0.0)` — the kernel reading via
            // `dev_ptr` observes zeros after the next stream-sync barrier.
            //
            // Cross-fold persistence is wrong here: the policy at fold N+1
            // is a different model than fold N, so visit counts from N
            // would mis-classify N+1's state-action distribution as
            // already-explored. FoldReset is the correct semantics — the
            // hash function (the projection matrix) stays frozen for
            // reproducibility, but the visit-count table re-cold-starts.
            //
            // The 42×16 SimHash projection matrix on `novelty_simhash_proj`
            // is intentionally NOT in this registry — it's the hash
            // function, not state, and must outlive every fold for
            // reproducibility (different runs with same seed get same
            // hash function).
            RegistryEntry {
                name: "sp11_novelty_hash",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.novelty_hash_buf — SP11 Fix 39 SimHash novelty visit-count hash table (1M slots × f32 = 4 MB mapped-pinned). Cleared at fold boundary so the new fold's policy starts with a clean visit-count → 1.0 novelty signal everywhere → maximal exploration pressure during the fold's cold-start window. The dispatch arm zero-fills via `host_slice_mut().fill(0.0)` — CPU writing a literal zero (NOT compute) per `feedback_no_htod_htoh_only_mapped_pinned.md`. The companion 42×16 SimHash projection matrix at `novelty_simhash_proj` is NOT in this registry — it's the hash function (frozen at trainer init from `SP11_PROJ_SEED_SALT`) and must outlive every fold for reproducibility.",
            },
            RegistryEntry {
                name: "sp11_reward_popart_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_POPART_WEIGHT_INDEX=340] — SP11 Fix 39 PopArt reward component weight. Produced by `reward_subsystem_controller_kernel` from improvement_z + per-component mag-ratio canaries (winner/diversifier blend). Consumed in unified-reward composition (Layer B). FoldReset sentinel 0; Pearl A bootstraps from the first controller emit (per `pearl_first_observation_bootstrap.md`). Spec: docs/superpowers/specs/2026-05-04-sp11-reward-as-controlled-subsystem.md §3.3.",
            },
            RegistryEntry {
                name: "sp11_reward_cf_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_CF_WEIGHT_INDEX=341] — SP11 Fix 39 counterfactual (CF) reward component weight. Produced by `reward_subsystem_controller_kernel`. Consumed in `mse_loss_kernel` and `c51_loss_kernel` (Layer B replaces the hardcoded `cf_weight=0.3f`). FoldReset sentinel 0; Pearl A bootstraps from the first controller emit (per `pearl_first_observation_bootstrap.md`). Spec §3.3.",
            },
            RegistryEntry {
                name: "sp11_reward_trail_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_TRAIL_WEIGHT_INDEX=342] — SP11 Fix 39 trail-stop reward component weight. Produced by `reward_subsystem_controller_kernel`. Consumed in trail-shaping reward path (Layer B). FoldReset sentinel 0; Pearl A bootstraps from the first controller emit. Spec §3.3.",
            },
            RegistryEntry {
                name: "sp11_reward_micro_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_MICRO_WEIGHT_INDEX=343] — SP11 Fix 39 microstructure reward component weight. Produced by `reward_subsystem_controller_kernel`. Consumed in microstructure-shaping reward path (Layer B). FoldReset sentinel 0; Pearl A bootstraps from the first controller emit. Spec §3.3.",
            },
            RegistryEntry {
                name: "sp11_reward_opp_cost_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_OPP_COST_WEIGHT_INDEX=344] — SP11 Fix 39 opportunity-cost reward component weight. Produced by `reward_subsystem_controller_kernel`. Consumed in opportunity-cost shaping reward path (Layer B). FoldReset sentinel 0; Pearl A bootstraps from the first controller emit. Spec §3.3.",
            },
            RegistryEntry {
                name: "sp11_reward_bonus_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_BONUS_WEIGHT_INDEX=345] — SP11 Fix 39 exploration-bonus reward component weight. Produced by `reward_subsystem_controller_kernel`. Consumed in bonus-shaping reward path (Layer B). FoldReset sentinel 0; Pearl A bootstraps from the first controller emit. Spec §3.3.",
            },
            RegistryEntry {
                name: "sp11_curiosity_pressure",
                category: ResetCategory::FoldReset,
                description: "ISV[CURIOSITY_PRESSURE_INDEX=346] — SP11 Fix 39 curiosity-pressure scalar. Produced by `reward_subsystem_controller_kernel` from val-sharpe trend + mag-ratio dispersion. Consumed at REPLAY-time (not collect-time) as `r_with_curiosity = r_base + curiosity_pressure · novelty_signal(state, action)`. Curiosity-bound capped at `SP11_CURIOSITY_BOUND_FRACTION=0.3 × pnl_reward_magnitude_ema`, with a permanent-fraction floor of `SP11_CURIOSITY_PERMANENT_FRACTION=0.2 × bound` per `pearl_blend_formulas_must_have_permanent_floor.md`. FoldReset sentinel 0; Pearl A bootstraps. Spec §3.3, §3.4.2.",
            },
            RegistryEntry {
                name: "sp11_saboteur_intensity_mult",
                category: ResetCategory::FoldReset,
                description: "ISV[SABOTEUR_INTENSITY_MULT_INDEX=347] — SP11 Fix 39 saboteur curriculum intensity multiplier. Produced by `reward_subsystem_controller_kernel` from saboteur_engagement_rate canary. Consumed in `gpu_experience_collector` (Layer B multiplies `saboteur_perturbation_scale` by this slot). Clamped to `[SP11_SABOTEUR_MIN=0.5, SP11_SABOTEUR_MAX=2.0]` (Invariant-1 rate-limiter anchor per `feedback_isv_for_adaptive_bounds.md` §3.4.2). FoldReset sentinel 0; Pearl A bootstraps. Spec §3.3, §3.4.2.",
            },
            RegistryEntry {
                name: "sp11_reward_weight_floor",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_WEIGHT_FLOOR_INDEX=348] — SP11 Fix 39 controller-output minimum-weight floor (`SP11_WEIGHT_FLOOR_FRACTION=0.5 × hard_floor`). Produced by `reward_subsystem_controller_kernel`. Consumed by the controller itself (re-read on next step) to enforce that no reward component drops below `SP11_WEIGHT_HARD_FLOOR=0.01` after blending — Invariant-1 rate-limiter floor preventing winner-take-all collapse. FoldReset sentinel 0; Pearl A bootstraps. Spec §3.4.2.",
            },
            RegistryEntry {
                name: "sp11_curiosity_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[CURIOSITY_BOUND_INDEX=349] — SP11 Fix 39 curiosity-pressure structural cap (`SP11_CURIOSITY_BOUND_FRACTION=0.3 × pnl_reward_magnitude_ema`). Produced by `reward_subsystem_controller_kernel`. Consumed at the curiosity-pressure clamp — keeps curiosity scaled to the run's PnL magnitude rather than a tuned constant per `feedback_isv_for_adaptive_bounds.md`. FoldReset sentinel 0; Pearl A bootstraps. Spec §3.4.2.",
            },
            RegistryEntry {
                name: "sp11_val_sharpe_delta_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VAL_SHARPE_DELTA_EMA_INDEX=350] — SP11 Fix 39 val-sharpe trend canary. Produced by `val_sharpe_delta_compute_kernel` (two-pass delta_ema + delta_var_ema, A1). Smoothed by Pearls A+D via chained `apply_pearls_ad_kernel` per `feedback_no_cpu_compute_strict.md`. Consumed by the SP11 controller as the improvement_z numerator. FoldReset sentinel 0; Pearl A bootstraps from the first val-sharpe sample of the new fold. Spec §3.3.1.",
            },
            RegistryEntry {
                name: "sp11_val_sharpe_var_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[VAL_SHARPE_VAR_EMA_INDEX=351] — SP11 Fix 39 val-sharpe variance canary (squared-deviation EMA against the running delta_ema). Produced alongside `sp11_val_sharpe_delta_ema` by `val_sharpe_delta_compute_kernel` (A1). Smoothed by Pearls A+D. Consumed by the SP11 controller as the improvement_z denominator (`improvement_z = delta_ema / sqrt(var_ema + SP11_EPS_DIV)`). FoldReset sentinel 0; Pearl A bootstraps. Spec §3.3.1.",
            },
            RegistryEntry {
                name: "sp11_reward_component_mag_ratios",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_COMPONENT_MAG_RATIO_BASE=352..358) — SP11 Fix 39 per-component reward-magnitude ratios (6 contiguous slots: popart, cf, trail, micro, opp_cost, bonus). Produced by `reward_component_mag_ratio_compute_kernel` (A1) reading existing per-component reward-magnitude EMAs (`REWARD_POPART_EMA_INDEX..+6`) and normalising to a unit simplex. Smoothed by Pearls A+D via chained `apply_pearls_ad_kernel`. Consumed by the SP11 controller for the winner_weight / diversifier_weight blend. The single registry entry covers the whole 6-slot block — the dispatch arm zeroes all 6 with one loop, matching the `sp5_pnl_aggregation` block-reset pattern. Per `feedback_trust_code_not_docs.md`: spec §3.3.1 said `grad EMA` but the SP4 grad-balancer is per-branch (4 slots), not per-reward-component — code wins, terminology corrected to `mag-ratio` (semantics for the controller are equivalent). FoldReset sentinel 0; Pearl A bootstraps. Spec §3.3.1.",
            },
            RegistryEntry {
                name: "sp11_saboteur_engagement_rate",
                category: ResetCategory::FoldReset,
                description: "ISV[SABOTEUR_ENGAGEMENT_RATE_INDEX=358] — SP11 Fix 39 saboteur engagement-rate canary (per-bar fraction of bars where the saboteur curriculum was actively perturbing experience tuples). Produced by `saboteur_engagement_compute_kernel` (A1) — block tree-reduce over the per-bar engagement flag, then EMA. Smoothed by Pearls A+D. Consumed by the SP11 controller to drive `saboteur_intensity_mult` toward the engagement floor (`SP11_ENGAGEMENT_FLOOR=0.1`). FoldReset sentinel 0; Pearl A bootstraps. Spec §3.3.1.",
            },
            RegistryEntry {
                name: "sp11_pnl_reward_magnitude_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[PNL_REWARD_MAGNITUDE_EMA_INDEX=359] — SP11 Fix 39 PnL-reward magnitude EMA (running `|reward_total|` smoothed with Wiener-α). Produced by the unified-reward kernel chain (existing producer; SP11 wires the EMA output to this slot in A1 alongside the val-sharpe and engagement canaries). Consumed by the SP11 controller as the curiosity-bound scale factor (`curiosity_bound = SP11_CURIOSITY_BOUND_FRACTION=0.3 × this slot`) per `feedback_isv_for_adaptive_bounds.md` §3.4.2. FoldReset sentinel 0; Pearl A bootstraps. Spec §3.3.1, §3.4.2.",
            },
            RegistryEntry {
                name: "sp11_popart_component_mag_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[POPART_COMPONENT_MAG_EMA_INDEX=360] — SP11 Fix 39 B1b fix-up popart-component-specific magnitude EMA. Produced by `popart_component_ema_kernel` (block tree-reduce over the per-bar `popart_component_per_sample` GPU buffer populated by `experience_env_step` at the `r_popart = capped_pnl;` voluntary-exit branch); smoothed by Pearls A+D via chained `apply_pearls_ad_kernel` (n_slots=1). Consumed by the SP11 mag-ratio canary as the popart axis input — replaces ISV[REWARD_POPART_EMA_INDEX=63]'s overloaded role as 'popart's signal' with a popart-component-specific value. Pre-fix-up slot 63 was overloaded (PopArt's normalisation input AND popart-component magnitude collapsed to the same value because reward composition was inline accumulation); B1b's structural decomposition surfaced the contamination — controller redistributed weight toward popart (w_pop ≈ 2.0) based on a contaminated ratio → 10× sharpe drop in B1b smoke. Slot 63 unchanged (PopArt's input = total reward magnitude, pre-SP11 invariant preserved). FoldReset sentinel 0; Pearl A bootstraps from the first observation. Spec §4 amendment 'Why slot 360'.",
            },
            RegistryEntry {
                name: "sp11_reward_component_var_emas",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_COMPONENT_VAR_EMA_BASE=361..367) — SP11 Fix 39 B1b smoke-recovery (2026-05-04, spec §4 amendment 'Why z-score' lines 564-619) per-reward-component variance EMAs (6 contiguous slots: popart at 361, then cf 362, trail 363, micro 364, opp_cost 365, bonus 366). Slot 361 is produced alongside the popart-component magnitude EMA by the extended `popart_component_ema_kernel` via single-pass two-tree-reduce Welford (mean → var); slots 362..367 are produced alongside the non-popart magnitudes by the extended `reward_component_ema_kernel` via per-thread Welford (component 0/popart variance is split off because slot 63 is the pre-SP11 total-reward magnitude EMA, not popart-component magnitude — see slot-360 fix-up rationale). All 6 variances are smoothed by Pearls A+D via chained `apply_pearls_ad_kernel` (n_slots=1 for popart variance at slot 361, n_slots=5 for the contiguous block at slots 362..367). Consumed by `reward_component_mag_ratio_compute_kernel` for z-score normalisation: `z[c] = mag[c] / max(sqrt(var[c]), EPS_DIV)` then `ratio[c] = z[c] / sum_z`. Replaces the linear `winner_weight = mag_ratio` formula that amplified popart's intrinsic O(100) magnitude over the other components' O(0.1-2) — w_pop saturated to MAX_WEIGHT, curiosity_b exploded, sharpe collapsed in B1b smoke `smoke-test-6wd2c` on commit `61b2fa962`. The single registry entry covers the whole 6-slot block — the dispatch arm zeroes all 6 with one loop, matching the `sp11_reward_component_mag_ratios` block-reset pattern. FoldReset sentinel 0; Pearl A bootstraps the variance from the first observation alongside its paired magnitude.",
            },
            // ── SP13 (2026-05-04): redefine success for predictive skill ─────
            //
            // Phase 0a Task T1: register the two dir-acc EMA slots so the
            // fold-boundary path resets them to the random-guessing sentinel
            // 0.5 (NOT 0.0 — directional accuracy has a meaningful baseline at
            // 50%, and Pearl A's first-observation replacement fires on the
            // first epoch of the new fold to track the new fold's signal
            // without contamination from the previous fold's terminal value).
            //
            // Slots 372 (TARGET_DIR_ACC), 376..380 (DIR_SKILL_BONUS_ALPHA/BETA,
            // LUCK_WIN_DISCOUNT, SKILL_BONUS_CAP_RATIO) are constructor-
            // initialised Invariant-1 anchors and need NO registry entry —
            // they must never reach sentinel 0 between folds, so the
            // constructor-write path keeps them populated with their defaults
            // for the lifetime of the trainer. Slot 375 (AUX_DIR_PREDICTION)
            // is per-bar overwritten by the aux head and needs no reset
            // entry either. Spec: docs/superpowers/specs/2026-05-04-sp13-redefine-success-for-predictive-skill.md
            RegistryEntry {
                name: "sp13_aux_dir_acc_short_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_DIR_ACC_SHORT_EMA_INDEX=373] — SP13 Phase 0a fast EMA of directional accuracy (α=0.3). Produced by `apply_fixed_alpha_ema_kernel` chained off `aux_dir_acc_reduce_kernel` (the fixed-α applicator preserves the short/long timescale split that Wiener-optimal `apply_pearls_ad_kernel` would collapse). Consumed by the Phase 0b aux-w controller as the deficit numerator (`deficit = max(0, target − short)`) and the stagnation comparator. FoldReset sentinel 0.5 (random-guessing baseline) so Pearl A bootstraps from the new fold's first observation per `pearl_first_observation_bootstrap.md` — the EMA tracks the new fold's signal without bias from the previous fold's terminal accuracy. Spec §implementation phases.",
            },
            RegistryEntry {
                name: "sp13_aux_dir_acc_long_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_DIR_ACC_LONG_EMA_INDEX=374] — SP13 Phase 0a slow EMA of directional accuracy (α=0.05) feeding the stagnation detector. Produced by `apply_fixed_alpha_ema_kernel` chained off `aux_dir_acc_reduce_kernel` (the fixed-α applicator preserves the short/long timescale split that Wiener-optimal `apply_pearls_ad_kernel` would collapse). Consumed by the Phase 0b aux-w controller's stagnation term (`stagnation = max(0, 1 − (short − long) / max(0.005, deficit))`) so a stalled short EMA decays aux_w back toward base — the deliberate 'we tried, it didn't help' signal that distinguishes Phase 0b's controller from SP11's inverted formula. FoldReset sentinel 0.5 (random-guessing baseline) so Pearl A bootstraps from the new fold's first observation per `pearl_first_observation_bootstrap.md`. Spec §implementation phases.",
            },
            // SP13 v3 P0a.T3 (2026-05-04): Hold-pricing observed-rate EMA.
            // Slots 380 (HOLD_COST) and 381 (HOLD_RATE_TARGET) are
            // constructor-initialised Invariant-1 anchors and need NO
            // registry entry — slot 380 is rewritten every step by the
            // host-side controller in `training_loop.rs`, and slot 381 is
            // a static default (0.20) that must never reach sentinel 0
            // between folds. Slot 382 is the per-fold observed-rate EMA
            // produced by `apply_fixed_alpha_ema_kernel` chained off
            // `hold_rate_observer_kernel`; sentinel 0.0 lets Pearl A
            // bootstrap from the new fold's first observation per
            // `pearl_first_observation_bootstrap.md` so the EMA tracks
            // the new fold's Hold-rate without bias from the previous
            // fold's terminal value.
            RegistryEntry {
                name: "sp13_hold_rate_observed_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_RATE_OBSERVED_EMA_INDEX=382] — SP13 v3 P0a.T3 per-fold EMA of the per-step Hold-pick rate `count(action_dir == DIR_HOLD) / batch_size`. Produced by `apply_fixed_alpha_ema_kernel` chained off `hold_rate_observer_kernel` (added in P0a.T3). Consumed by the host-side Hold-cost controller in `training_loop.rs`: `excess = max(0, observed − target); hold_cost = HOLD_COST_BASE × (1 + 5 × excess)` clamped to `[0.5×base, 5.0×base]`, written to ISV[HOLD_COST_INDEX=380]. The reward-composition site in `experience_kernels.cu` then subtracts the cost on every Hold-action bar — pricing the action so the policy uses Hold deliberately rather than as a free CQL-bias-anchored default. FoldReset sentinel 0.0 so Pearl A bootstraps from the new fold's first observation; the controller relaxes back to baseline cost (HOLD_COST_BASE × 0.5 floor) when observed ≤ target. Spec §'Change 1: Price Hold (replaces v2's Eliminate Hold)'.",
            },
            // ── SP14 q_disagreement diagnostic — fold-reset slots ───────────
            // SP14 Layer C Phase C.1 (2026-05-08) deleted the α-machinery
            // registry entries (sp14_k_aux_adaptive, sp14_k_q_adaptive,
            // sp14_beta_rate_limiter_adaptive, sp14_aux_dir_acc_variance_ema,
            // sp14_alpha_grad_raw_variance_ema, sp14_gate1_open_state,
            // sp14_alpha_grad_smoothed, sp14_aux_dir_acc_post_open_min,
            // and the GRADIENT_HACK_LOCKOUT_REMAINING comment) atomically
            // with the kernels and slot constants. The 3 q_disagreement
            // diagnostic slots remain (HEALTH_DIAG consumer chain).
            // Spec: docs/superpowers/specs/2026-05-05-sp14-aux-q-wire-earned-gradient-flow.md
            // Phase C.1 deletion: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md
            RegistryEntry {
                name: "sp14_q_disagreement_short_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_DISAGREEMENT_SHORT_EMA_INDEX=383] — SP14 fast EMA (α=0.3) of per-step K=4↔K=2 mapped argmax disagreement with Hold/Flat masked. Produced by `q_disagreement_update_kernel` every training step. HEALTH_DIAG diagnostic only post-Phase C.1 (the α-machinery consumer was deleted). FoldReset sentinel SENTINEL_Q_DISAGREEMENT=0.5 (analytic random alignment under masking) so Pearl A bootstraps from the new fold's first observation per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-05-sp14-aux-q-wire-earned-gradient-flow.md.",
            },
            RegistryEntry {
                name: "sp14_q_disagreement_long_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_DISAGREEMENT_LONG_EMA_INDEX=384] — SP14 slow EMA (α=0.05) of per-step K=4↔K=2 mapped argmax disagreement with Hold/Flat masked. Produced by `q_disagreement_update_kernel` every training step. HEALTH_DIAG diagnostic only post-Phase C.1. FoldReset sentinel SENTINEL_Q_DISAGREEMENT=0.5 so Pearl A bootstraps from the new fold's first observation. Spec: docs/superpowers/specs/2026-05-05-sp14-aux-q-wire-earned-gradient-flow.md.",
            },
            RegistryEntry {
                name: "sp14_q_disagreement_variance_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_DISAGREEMENT_VARIANCE_EMA_INDEX=389] — SP14 Welford variance EMA of per-step Q-disagreement signal (Welford one-pass, α=0.05). HEALTH_DIAG diagnostic only post-Phase C.1 (its k_q adaptive consumer was deleted with the α-machinery). FoldReset sentinel SENTINEL_VARIANCE=0.0 — Pearl A bootstrap. Produced by `q_disagreement_update_kernel`. Spec: docs/superpowers/specs/2026-05-05-sp14-aux-q-wire-earned-gradient-flow.md.",
            },

            // ── SP14 Layer C aux trunk control plane (Phase C.1, 2026-05-08) ──
            // 5 Adam hyperparameter Invariant-1 anchors + 1 Pearl-A
            // first-observation EMA. Plan:
            // docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md
            RegistryEntry {
                name: "sp14_c_aux_trunk_lr",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_TRUNK_LR_INDEX=444] — SP14 Layer C aux-trunk Adam learning rate. Invariant-1 anchor (NOT a stateful EMA) per `feedback_isv_for_adaptive_bounds.md`. FoldReset rewrites AUX_TRUNK_LR_DEFAULT=1e-4 so the aux trunk's optimiser uses a sane default until any future adaptive controller drives the slot. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.1.",
            },
            RegistryEntry {
                name: "sp14_c_aux_trunk_beta1",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_TRUNK_BETA1_INDEX=445] — SP14 Layer C aux-trunk Adam β1. Invariant-1 anchor; FoldReset rewrites AUX_TRUNK_BETA1_DEFAULT=0.9. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.1.",
            },
            RegistryEntry {
                name: "sp14_c_aux_trunk_beta2",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_TRUNK_BETA2_INDEX=446] — SP14 Layer C aux-trunk Adam β2. Invariant-1 anchor; FoldReset rewrites AUX_TRUNK_BETA2_DEFAULT=0.999. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.1.",
            },
            RegistryEntry {
                name: "sp14_c_aux_trunk_eps",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_TRUNK_EPS_INDEX=447] — SP14 Layer C aux-trunk Adam ε. Invariant-1 anchor; FoldReset rewrites AUX_TRUNK_EPS_DEFAULT=1e-8. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.1.",
            },
            RegistryEntry {
                name: "sp14_c_aux_trunk_grad_clip",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_TRUNK_GRAD_CLIP_INDEX=448] — SP14 Layer C aux-trunk Adam grad-clip norm threshold. Invariant-1 anchor; FoldReset rewrites AUX_TRUNK_GRAD_CLIP_DEFAULT=1.0. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.1.",
            },
            RegistryEntry {
                name: "sp14_c_h_s2_aux_rms_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[H_S2_AUX_RMS_EMA_INDEX=449] — SP14 Layer C aux-trunk output RMS EMA (mirrors GRN trunk's H_S2_RMS_EMA_INDEX=96 for the new aux trunk's `h_s2_aux` output). Stateful kernel output produced in Phase C.6 by `h_s2_aux_rms_ema_kernel`. FoldReset sentinel SENTINEL_H_S2_AUX_RMS=0.0 — Pearl-A first-observation bootstrap per `pearl_first_observation_bootstrap.md`. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.1.",
            },
            // ── SP14 Layer C Phase C.4b (2026-05-08): aux prediction horizon ──
            // Two slots [450, 451] driving the new ISV-driven aux label
            // horizon. AUX_PRED_HORIZON_BARS_INDEX=450 is the H consumed by
            // both `aux_sign_label_kernel.cu` and
            // `aux_sign_label_per_step_kernel.cu`; sentinel 60.0 (≈1hr @
            // 1-min bars) is the cold-start default until the adaptive
            // producer (`aux_horizon_update_kernel`) lands the first
            // observation. AVG_WIN_HOLD_TIME_BARS_INDEX=451 is the EMA
            // target produced by `avg_win_hold_time_update_kernel` from
            // the existing per-sample `hold_at_exit_per_sample` +
            // `trade_profitable_per_sample` buffers; sentinel 0.0 is the
            // Pearl-A bootstrap value (no winning trades observed yet).
            RegistryEntry {
                name: "sp14_c4b_aux_pred_horizon_bars",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_PRED_HORIZON_BARS_INDEX=450] — SP14 Layer C Phase C.4b adaptive aux prediction horizon H. Read by `aux_sign_label_kernel.cu` + `aux_sign_label_per_step_kernel.cu` to compute label = (p[bar+H] > p[bar]). FoldReset sentinel SENTINEL_AUX_PRED_HORIZON_BARS=60.0 (≈1hr @ 1-min bars). Pearl-A first-observation bootstrap on first valid winning-trade observation; Wiener-α slow EMA blend (α=0.01 fixed) thereafter via `aux_horizon_update_kernel`. Plan: docs/superpowers/plans/2026-05-07-sp14-layer-c-separate-aux-trunk.md §C.4b.",
            },
            RegistryEntry {
                name: "sp14_c4b_avg_win_hold_time_bars",
                category: ResetCategory::FoldReset,
                description: "ISV[AVG_WIN_HOLD_TIME_BARS_INDEX=451] — SP14 Layer C Phase C.4b avg winning hold time EMA (bars). Aggregated from `hold_at_exit_per_sample` + `trade_profitable_per_sample` per-sample buffers (populated by `unified_env_step_core` in `experience_kernels.cu`) by `avg_win_hold_time_update_kernel` at per-epoch boundary. FoldReset sentinel SENTINEL_AVG_WIN_HOLD_TIME_BARS=0.0 — Pearl-A first-observation bootstrap. Drives the horizon producer for ISV[450]. Plan: §C.4b.",
            },
            // ── Class A P0-A (2026-05-08): adaptive REWARD_POS/NEG_CAP ──
            // Two slots [452, 453] replacing the hardcoded
            // `REWARD_POS_CAP=+5.0f` / `REWARD_NEG_CAP=-10.0f`
            // (state_layout.cuh:266-267) per Class A audit. Producer
            // kernel `reward_cap_update_kernel` computes
            // p99(winning_returns) × 1.5 → POS cap, NEG = −2 × POS,
            // writes both at per-epoch boundary. Pearl-A bootstrap
            // sentinels match pre-P0-A hardcoded constants for
            // bit-identical cold-start behavior — consumers fall back
            // to the macro when the ISV slot is at sentinel. Once the
            // first valid observation lands the adaptive path takes
            // over via Welford α=0.01 slow EMA (reward distribution
            // is the foundation of training; shouldn't move fast).
            // Per `feedback_isv_for_adaptive_bounds.md` and
            // `pearl_audit_unboundedness_for_implicit_asymmetry.md`.
            RegistryEntry {
                name: "sp14_p0a_reward_pos_cap_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_POS_CAP_ADAPTIVE_INDEX=452] — Class A P0-A adaptive positive reward cap (replaces hardcoded REWARD_POS_CAP=+5.0f from state_layout.cuh:266). Produced by `reward_cap_update_kernel` from p99(winning_returns) × safety_factor=1.5 over the per-epoch `step_ret_per_sample` + `trade_close_per_sample` buffers. FoldReset sentinel SENTINEL_REWARD_POS_CAP=5.0 — Pearl-A first-observation bootstrap (matches pre-P0-A hardcoded value for bit-identical cold-start). Welford α=0.01 slow EMA thereafter. Bounds [1, 50] — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`. Consumed by experience_kernels.cu (segment_complete cap), compute_sp15_final_reward_kernel.cu (Stage 4 cap), and sp15_reward_axis_helpers.cuh (sp15_apply_sp12_cap helper). Per Class A audit (highest-suspected-impact fix for the months-long WR-stuck-at-46-48% plateau across 11 superprojects).",
            },
            RegistryEntry {
                name: "sp14_p0a_reward_neg_cap_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_NEG_CAP_ADAPTIVE_INDEX=453] — Class A P0-A adaptive negative reward cap (replaces hardcoded REWARD_NEG_CAP=-10.0f from state_layout.cuh:267). Produced by `reward_cap_update_kernel` as NEG = −REWARD_NEG_TO_POS_RATIO=2.0 × POS_CAP. The 2:1 ratio (Kahneman/Tversky meta-analysis ~2.0-2.25) is preserved at producer-time inside the kernel (single source of truth — no consumer applies the multiplier itself), per `pearl_audit_unboundedness_for_implicit_asymmetry`. FoldReset sentinel SENTINEL_REWARD_NEG_CAP=-10.0 (matches pre-P0-A hardcoded value for bit-identical cold-start). Resulting bounds [-100, -2] derived from POS bounds × ratio. Consumed alongside POS slot at the same 3 sites.",
            },
            // ── Class A P1-Producer (2026-05-08): adaptive Bayesian Kelly priors ──
            // Four slots [454..458) replacing the hardcoded
            // `prior_wins=2.0f / prior_losses=2.0f / prior_sum_wins=0.01f /
            // prior_sum_losses=0.01f` constants in
            // `kelly_cap_update_kernel.cu:39-42` and
            // `trade_physics.cuh::kelly_position_cap:304-307`. Producer
            // kernel `kelly_bayesian_priors_update_kernel` aggregates
            // realized PS_KELLY_{WIN_COUNT, LOSS_COUNT, SUM_WINS,
            // SUM_LOSSES} across envs from the same `portfolio_state` buffer
            // `kelly_cap_update_kernel` reads from at the same per-epoch
            // boundary, then slow-EMA-blends into the four slots. Pearl-A
            // bootstrap sentinels (2.0/2.0/0.01/0.01) match the
            // pre-P1-Producer hardcoded values for bit-identical cold-start
            // behavior — consumers fall back to the static defaults via the
            // NULL-tolerant + range guard pattern (mirrors the existing
            // `kelly_f_smooth` / `kelly_warmup_floor_sp9` patterns in
            // `unified_env_step_core`). Once the first valid observation
            // lands the adaptive path takes over via slow EMA (α=0.005;
            // per-fold cadence — the Bayesian prior is a *prior belief*
            // and should change slowly across folds). Per
            // `feedback_isv_for_adaptive_bounds.md` and
            // `pearl_controller_anchors_isv_driven.md`.
            RegistryEntry {
                name: "sp14_p1_kelly_prior_wins",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_PRIOR_WINS_INDEX=454] — Class A P1-Producer adaptive Bayesian prior_wins (replaces hardcoded prior_wins=2.0f from kelly_cap_update_kernel.cu:39 + trade_physics.cuh::kelly_position_cap:304). Produced by `kelly_bayesian_priors_update_kernel` from the realized PS_KELLY_WIN_COUNT field aggregated across envs in the per-epoch `portfolio_state` buffer. FoldReset sentinel SENTINEL_KELLY_PRIOR_WINS=2.0 — Pearl-A first-observation bootstrap (matches pre-P1-Producer hardcoded value for bit-identical cold-start). α=0.005 slow EMA thereafter. Bounds [0.5, 100] — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`. Consumed by kelly_cap_update_kernel (cold-path epoch-boundary effective Kelly cap) and trade_physics.cuh::kelly_position_cap (per-step env Kelly cap, NULL-tolerant via threaded `isv_signals_ptr`).",
            },
            RegistryEntry {
                name: "sp14_p1_kelly_prior_losses",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_PRIOR_LOSSES_INDEX=455] — Class A P1-Producer adaptive Bayesian prior_losses (replaces hardcoded prior_losses=2.0f from kelly_cap_update_kernel.cu:40 + trade_physics.cuh::kelly_position_cap:305). Produced by `kelly_bayesian_priors_update_kernel` from the realized PS_KELLY_LOSS_COUNT field aggregated across envs in the per-epoch `portfolio_state` buffer. FoldReset sentinel SENTINEL_KELLY_PRIOR_LOSSES=2.0 — Pearl-A first-observation bootstrap (matches pre-P1-Producer hardcoded value for bit-identical cold-start). α=0.005 slow EMA thereafter. Bounds [0.5, 100] same as prior_wins. Consumed at the same 2 sites as prior_wins.",
            },
            RegistryEntry {
                name: "sp14_p1_kelly_prior_sum_wins",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_PRIOR_SUM_WINS_INDEX=456] — Class A P1-Producer adaptive Bayesian prior_sum_wins (replaces hardcoded prior_sum_wins=0.01f from kelly_cap_update_kernel.cu:41 + trade_physics.cuh::kelly_position_cap:306). Produced by `kelly_bayesian_priors_update_kernel` from the realized PS_KELLY_SUM_WINS field aggregated across envs in the per-epoch `portfolio_state` buffer. FoldReset sentinel SENTINEL_KELLY_PRIOR_SUM_WINS=0.01 — Pearl-A first-observation bootstrap (matches pre-P1-Producer hardcoded value for bit-identical cold-start). α=0.005 slow EMA thereafter. Bounds [0.001, 1.0] — sum below 1e-3 hits the `fmaxf(avg_loss, 0.0001f)` numerical floor; sum above 1.0 implies > 100% per-trade equity which is risk-management-failure territory. Consumed at the same 2 sites as prior_wins.",
            },
            RegistryEntry {
                name: "sp14_p1_kelly_prior_sum_losses",
                category: ResetCategory::FoldReset,
                description: "ISV[KELLY_PRIOR_SUM_LOSSES_INDEX=457] — Class A P1-Producer adaptive Bayesian prior_sum_losses (replaces hardcoded prior_sum_losses=0.01f from kelly_cap_update_kernel.cu:42 + trade_physics.cuh::kelly_position_cap:307). Produced by `kelly_bayesian_priors_update_kernel` from the realized PS_KELLY_SUM_LOSSES field aggregated across envs in the per-epoch `portfolio_state` buffer. FoldReset sentinel SENTINEL_KELLY_PRIOR_SUM_LOSSES=0.01 — Pearl-A first-observation bootstrap (matches pre-P1-Producer hardcoded value for bit-identical cold-start). α=0.005 slow EMA thereafter. Bounds [0.001, 1.0] same as prior_sum_wins. Consumed at the same 2 sites as prior_wins.",
            },
            // ── Class A audit-fix Batch 4-A (2026-05-08): adaptive DD saturation floor ──
            // Single slot [458..459) replacing the hardcoded `0.25f`
            // saturation floor in `trade_physics.cuh::apply_margin_cap`
            // (the upper end of the linear position-size scaling ramp).
            // Producer kernel `dd_saturation_floor_update_kernel`
            // aggregates per-env DD_MAX (offset 1) from the existing
            // `sp15_dd_state_per_env[n_envs * 6]` tile (same source as
            // `compute_sp15_final_reward_kernel` reads from at the same
            // per-epoch boundary), then slow-EMA-blends into the slot.
            // Pearl-A bootstrap sentinel (0.25) matches the pre-fix
            // hardcoded value for bit-identical cold-start behavior —
            // consumer falls back to DD_SATURATION_FLOOR_DEFAULT (0.25)
            // via the sentinel-detect + range-guard pattern (mirrors
            // the SP12-cap fallback in `sp15_apply_sp12_cap`). Once the
            // first valid observation lands the adaptive path takes over
            // via slow EMA (α=0.01; DD distribution is a slow-moving
            // fold-volatility property — same cadence as P0-A
            // REWARD_POS_CAP). Without this dispatch arm, the C.10
            // lesson recurs: the FoldReset registry entry exists, but
            // no actual reset fires — slot drifts across folds and the
            // layout-fingerprint smoke test eventually catches it as a
            // runtime crash.
            RegistryEntry {
                name: "sp14_audit_4a_dd_saturation_floor_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_SATURATION_FLOOR_ADAPTIVE_INDEX=458] — Class A audit-fix Batch 4-A adaptive DD saturation floor (replaces hardcoded `0.25f` in `trade_physics.cuh::apply_margin_cap`, the upper end of the linear position-size scaling ramp `dd_scale = max(0.05, 1.0 − dd_frac/saturation_floor)`). Produced by `dd_saturation_floor_update_kernel` from p75(per-env DD_MAX) × safety_factor=1.5 over the `dd_state_per_env[n_envs * 6]` tile (offset 1 = DD_MAX). FoldReset sentinel SENTINEL_DD_SATURATION_FLOOR=0.25 — Pearl-A first-observation bootstrap (matches pre-fix hardcoded value for bit-identical cold-start). Welford α=0.01 slow EMA thereafter. Bounds [0.10, 0.50] — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`. Distinct semantic role from SP15_DD_THRESHOLD_INDEX=421 (the SP15 quadratic DD-penalty trigger threshold, a lower bound). Consumed by `apply_margin_cap` at line ~154 (threaded `isv_signals_ptr`, NULL-tolerant cold-start fallback to DD_SATURATION_FLOOR_DEFAULT). Atomically wired with the legacy `compute_drawdown_penalty` deletion (Item 2 Case A) since SP15's quadratic asymmetric DD penalty in `compute_sp15_final_reward_kernel.cu:154` is the production-grade replacement; layering both creates double-counting.",
            },
            // ── Class A audit-fix Batch 4-B (2026-05-08): adaptive plan_threshold floor + MIN_HOLD_TEMPERATURE ──
            // Two slots [459..461) replacing (a) the hardcoded `0.1f`
            // floor in `plan_threshold_update_kernel.cu:44` and (b) the
            // deleted epoch-driven anneal schedule
            // `T_end + (T_start − T_end) × exp(-epoch / decay)` for
            // MIN_HOLD_TEMPERATURE.
            //
            // PLAN_THRESHOLD_FLOOR_ADAPTIVE (459) — Design Y inline
            // producer (no new kernel; the same
            // `plan_threshold_update_kernel` writes both slot 49 and
            // the slow-EMA-shadow floor at slot 459 in the same launch,
            // then uses the freshly-written floor as the lower bound
            // on the derived plan_threshold). FoldReset sentinel 0.1
            // matches the pre-fix hardcoded value for bit-identical
            // cold-start. α=0.005 slow EMA (per-fold cadence; the
            // floor is a long-term shadow of `0.5 × readiness_ema`
            // and must move much slower than the readiness EMA itself).
            // Bounds [0.05, 0.50] are Category-1 dimensional safety
            // floors per `feedback_isv_for_adaptive_bounds`.
            //
            // MIN_HOLD_TEMPERATURE_ADAPTIVE (460) — Producer kernel
            // `min_hold_temperature_update_kernel` reads
            // `ISV[AUX_DIR_ACC_SHORT_EMA_INDEX=373]` (sp13 fast EMA of
            // binary directional accuracy), maps it to a [5, 50]
            // temperature via
            // `temp = TEMP_MIN + (TEMP_MAX − TEMP_MIN) × clamp((short_ema
            // − 0.5)/0.5, 0, 1)`, slow-EMA-blends into slot 460.
            // FoldReset sentinel 50.0 matches the deleted
            // MIN_HOLD_TEMPERATURE_START anchor for bit-identical
            // cold-start under both regimes (first epoch had T=50
            // under the old schedule too). α=0.05 mid-cadence EMA.
            // Bounds [5, 50] are Category-1 dimensional safety floors
            // per `feedback_isv_for_adaptive_bounds` (matches the
            // original schedule range MIN_HOLD_TEMPERATURE_END=5 ↔
            // MIN_HOLD_TEMPERATURE_START=50). Decouples temperature
            // from epoch number — the training loop now reads slot 460
            // via `DQNTrainer::read_min_hold_temperature_from_isv` to
            // seed the kernel-passed scalar (with cold-start fallback
            // to MIN_HOLD_TEMPERATURE_FALLBACK=50.0 when the slot is
            // at sentinel).
            //
            // Per `feedback_no_legacy_aliases.md` and
            // `feedback_no_partial_refactor.md` the legacy
            // `min_hold_temperature_for_epoch` helper +
            // MIN_HOLD_TEMPERATURE_{START, END, DECAY} #defines are
            // deleted atomically with this wiring (no half-migrated
            // state). Both call sites in training_loop.rs are
            // migrated to the new ISV reader in the same commit.
            //
            // Without these dispatch arms, the C.10 lesson recurs:
            // the FoldReset registry entry exists, but no actual reset
            // fires — slot drifts across folds and the layout-fingerprint
            // smoke test eventually catches it as a runtime crash.
            RegistryEntry {
                name: "sp14_audit_4b_plan_threshold_floor_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[PLAN_THRESHOLD_FLOOR_ADAPTIVE_INDEX=459] — Class A audit-fix Batch 4-B adaptive plan_threshold floor (replaces hardcoded `0.1f` in `plan_threshold_update_kernel.cu:44`, the lower bound of the derived plan_threshold = max(floor, 0.5 × readiness_ema)). Design Y inline producer: the same `plan_threshold_update_kernel` writes both ISV[PLAN_THRESHOLD_INDEX=49] and ISV[459] in the same launch — the floor tracks a slow EMA of `0.5 × readiness_ema` (the very expression the kernel uses as its derived threshold target) and the kernel uses the freshly-written floor as the lower bound. FoldReset sentinel SENTINEL_PLAN_THRESHOLD_FLOOR=0.1 — Pearl-A first-observation bootstrap (matches pre-fix hardcoded value for bit-identical cold-start). α=0.005 slow EMA thereafter (per-fold cadence; the floor is a long-term shadow and must move much slower than the readiness EMA itself which adapts at α≈[0.05, 0.10]). Bounds [0.05, 0.50] — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds.md` (probability units; below 5% the readiness gate is effectively absent, above 50% it is uselessly strict). Distinct from PLAN_THRESHOLD_INDEX=49 (the live derived threshold, fast cadence) — slot 459 is the slow-moving lower bound on slot 49.",
            },
            RegistryEntry {
                name: "sp14_audit_4b_min_hold_temperature_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[MIN_HOLD_TEMPERATURE_ADAPTIVE_INDEX=460] — SP16 Phase 1 (revised, 2026-05-08) adaptive MIN_HOLD_TEMPERATURE (replaces the DELETED epoch-driven anneal schedule `T_end + (T_start − T_end) × exp(-epoch / decay)` formerly at state_layout.cuh::MIN_HOLD_TEMPERATURE_{START=50, END=5, DECAY=20} + training_loop.rs::min_hold_temperature_for_epoch). Producer kernel `min_hold_temperature_update_kernel` reads ISV[HOLD_RATE_OBSERVED_EMA_INDEX=382] and ISV[HOLD_RATE_TARGET_INDEX=381] (sp13 hold-pricing chain) and maps the overrun into a [5, 50] temperature via `target_temp = TEMP_MIN + (TEMP_MAX − TEMP_MIN) × clamp(max(0, observed - target) / max(target, 0.01), 0, 1)`, slow-EMA-blends into slot 460. SIGNAL SWAPPED 2026-05-08 from ISV[AUX_DIR_ACC_SHORT_EMA_INDEX=373] — post-mortem of train-multi-seed-pfh9n showed slot 373 stayed at sentinel 0.5 in Fold 1 (per-step aux producer didn't push it off sentinel quickly enough OR binary classifier converged within ε of 0.5 in noisy environments), so the kernel's early-return-on-sentinel guard pinned slot 460 at 50 for the entire fold. Hold rates are measured per-epoch from realised actions and survive fold reset cleanly. Cold-start sentinel guard preserved: when observed_hold_rate is at SENTINEL_HOLD_RATE_OBSERVED=0.0 (matches sp13_hold_rate_observed_ema fold-reset sentinel), the kernel keeps slot 460 unchanged — consumer falls back to MIN_HOLD_TEMPERATURE_FALLBACK=50.0. FoldReset sentinel SENTINEL_MIN_HOLD_TEMPERATURE=50.0 — Pearl-A first-observation bootstrap (matches the deleted MIN_HOLD_TEMPERATURE_START=50 anchor for bit-identical cold-start; epoch-0 had T=50 under the old schedule too). SP16 T3 (2026-05-08): the hardcoded α=0.05 was replaced with Wiener-optimal α from Welford accumulators in slots [468..474). Bounds [5, 50] — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds.md` (matches the original schedule range). Per `compute_min_hold_penalty` at trade_physics.cuh:575 (`soft_factor = deficit / (deficit + T)`), HIGH T = forgiving (saturates → 0, no exit penalty), LOW T = sharp (saturates → 1, max exit penalty). Over-holding (overrun > 0) pushes temp HIGH (exit ramp); at-or-below target pushes temp LOW (strict commitment). Closed-loop control on the actual Hold-rate symptom rather than the (sentinel-masked) dir_acc proxy. Consumed by experience_kernels.cu via the kernel-passed `min_hold_temperature` scalar — the training loop seeds that scalar per-epoch via `DQNTrainer::read_min_hold_temperature_from_isv` (cold-start fallback to MIN_HOLD_TEMPERATURE_FALLBACK=50.0 when slot is at sentinel).",
            },
            // ── SP16 T3 (2026-05-08): Wiener-optimal Welford accumulators ────
            // 6 ISV slots [468..474) for the MIN_HOLD_TEMPERATURE (T1) producer.
            // Replace the hardcoded `α = 0.05f` literal in the producer kernel
            // with a signal-driven Wiener-optimal α per
            // `pearl_wiener_optimal_adaptive_alpha`:
            //
            //     α = diff_var / (diff_var + sample_var + ε)
            //
            // The block of 6 slots holds:
            //   - target_mean: Welford running mean of `target_temp`
            //   - target_M2: Welford ΣΔ² (sample variance accumulator)
            //   - diff_mean: Welford running mean of consecutive one-step diffs
            //   - diff_M2: Welford ΣΔ² for the diff series
            //   - prev_target: previous-epoch target value (for next diff calc)
            //   - sample_count: Welford counter (number of observations)
            //
            // FoldReset sentinel 0.0 across all 6 slots — combined with the
            // cold-start fallback (sample_count < 3 → α = 1.0 REPLACE), the
            // first observation of each new fold replaces blended directly,
            // the second observation seeds diff statistics, and α adapts from
            // the third observation onward. Per
            // `feedback_isv_for_adaptive_bounds.md` α was an adaptive bound
            // being hardcoded; this lifts the constant into the producer's
            // own statistics.
            RegistryEntry {
                name: "sp16_t3_mht_target_mean",
                category: ResetCategory::FoldReset,
                description: "ISV[MHT_TARGET_MEAN_INDEX=468] — SP16 T3 Welford running mean of target_temp for the MIN_HOLD_TEMPERATURE producer kernel. Sentinel 0.0; tracks `target_temp ∈ [5, 50]`.",
            },
            RegistryEntry {
                name: "sp16_t3_mht_target_m2",
                category: ResetCategory::FoldReset,
                description: "ISV[MHT_TARGET_M2_INDEX=469] — SP16 T3 Welford ΣΔ² for target_temp in the MIN_HOLD_TEMPERATURE producer kernel. Sentinel 0.0.",
            },
            RegistryEntry {
                name: "sp16_t3_mht_diff_mean",
                category: ResetCategory::FoldReset,
                description: "ISV[MHT_DIFF_MEAN_INDEX=470] — SP16 T3 Welford running mean of consecutive `target_temp` diffs in the MIN_HOLD_TEMPERATURE producer kernel. Sentinel 0.0.",
            },
            RegistryEntry {
                name: "sp16_t3_mht_diff_m2",
                category: ResetCategory::FoldReset,
                description: "ISV[MHT_DIFF_M2_INDEX=471] — SP16 T3 Welford ΣΔ² for the consecutive-diff series in the MIN_HOLD_TEMPERATURE producer kernel. Sentinel 0.0.",
            },
            RegistryEntry {
                name: "sp16_t3_mht_prev_target",
                category: ResetCategory::FoldReset,
                description: "ISV[MHT_PREV_TARGET_INDEX=472] — SP16 T3 previous-epoch `target_temp` for the MIN_HOLD_TEMPERATURE producer kernel. Sentinel 0.0.",
            },
            RegistryEntry {
                name: "sp16_t3_mht_sample_count",
                category: ResetCategory::FoldReset,
                description: "ISV[MHT_SAMPLE_COUNT_INDEX=473] — SP16 T3 Welford observation counter for the MIN_HOLD_TEMPERATURE producer kernel. Sentinel 0.0. Cold-start fallback (sample_count < 3 → α = 1.0) ensures the first 3 epochs of each fold force REPLACE so the Welford-derived α takes over from epoch 3 onward without a 60-epoch convergence lag.",
            },
            // ── SP15 Phase 1.2 (2026-05-06): cost-net sharpe slots ────────────
            // Two ISV slots [407, 408]:
            //   - OFI_IMPACT_LAMBDA_INDEX=407: Invariant-1 anchor (NOT a
            //     stateful EMA). Constructor-seeded to 2.0e-4 per spec §6.2;
            //     FoldReset rewrites the same anchor (NOT sentinel 0) so the
            //     cost kernel functions correctly on the new fold's first
            //     launch. Per-fold ISV refit may overwrite this in later
            //     phases; the FoldReset arm restores the default to break
            //     cold-start of each new fold (must never reach sentinel 0,
            //     which would silently disable the OFI-impact term).
            //   - COST_PER_BAR_AVG_INDEX=408: stateful kernel output
            //     (mean(cost_t)). FoldReset sentinel 0; Pearl A bootstraps
            //     from the new fold's first kernel launch per
            //     `pearl_first_observation_bootstrap.md`.
            // Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md.
            RegistryEntry {
                name: "sp15_ofi_impact_lambda",
                category: ResetCategory::FoldReset,
                description: "ISV[OFI_IMPACT_LAMBDA_INDEX=407] — SP15 Phase 1.2 (2026-05-06) OFI-impact lambda for the cost-net sharpe kernel (per spec §6.2). Per-side cost: `λ × |position| × |ofi| × side_ind`. Constant Invariant-1 anchor (2.0e-4) per `feedback_isv_for_adaptive_bounds.md` — NOT a stateful EMA. Constructor-seeded; FoldReset rewrites the same default so the cost kernel functions correctly on the new fold's first launch (must never reach sentinel 0, which would silently disable the OFI-impact term). Per-fold ISV refit may overwrite this in later phases; the reset path restores the default to break cold-start of each new fold. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.2.",
            },
            RegistryEntry {
                name: "sp15_cost_per_bar_avg",
                category: ResetCategory::FoldReset,
                description: "ISV[COST_PER_BAR_AVG_INDEX=408] — SP15 Phase 1.2 (2026-05-06) mean cost-per-bar emitted by the cost-net sharpe kernel (`sum(cost_t) / n` over the sharpe window). Stateful kernel output (NOT cross-fold persistent); FoldReset sentinel 0 so the new fold's first `launch_sp15_cost_net_sharpe` writes the new fold's true mean. Per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.2.",
            },
            // ── SP15 Phase 1.3 (2026-05-06): drawdown reporting slots ─────────
            // Six ISV slots [401..407) emitted by `dd_state_kernel`:
            //   - DD_CURRENT (401): per-step current drawdown ratio in [0, 1].
            //     FoldReset sentinel 0 (no DD at fold start; first kernel
            //     launch overwrites with the true value).
            //   - DD_MAX (402): running max of DD_CURRENT across the fold.
            //     FoldReset sentinel 0 (each fold's max-DD is independent;
            //     cross-fold persistence would silently drag the calmar
            //     denominator floor between folds).
            //   - DD_RECOVERY_BARS (403): bars since last new high-water mark.
            //     FoldReset sentinel 0 (new fold = fresh recovery counter).
            //   - DD_PERSISTENCE (404): twin counter to DD_RECOVERY_BARS in
            //     this phase (split-lifetime semantics may diverge in later
            //     phases). FoldReset sentinel 0 same rationale.
            //   - CALMAR (405): floored max-DD denominator for the host
            //     composer (`calmar = mean_pnl / value-here`). Kernel writes
            //     `max(dd_max, 1e-4)`; the floor eliminates the saturation-
            //     at-100 artifact seen in train-dd4xl HEALTH_DIAG. FoldReset
            //     sentinel 1e-4 so the very first calmar division at fold
            //     start uses the floor, not a sentinel 0 (which would yield
            //     ±inf and immediately re-trip the saturation guard).
            //   - DD_PCT (406): `clip(current_dd / max(dd_budget, 1e-4), 0, 1)`.
            //     FoldReset sentinel 0 (cold-start before first kernel
            //     launch).
            // Per spec §6.3. Reads PS_PEAK_EQUITY (slot 7) and PS_PREV_EQUITY
            // (slot 9) from the existing position state buffer — NO new ISV
            // equity slot (invariant verified during plan v2 critical
            // review).
            RegistryEntry {
                name: "sp15_dd_current",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_CURRENT_INDEX=401] — SP15 Phase 1.3 (2026-05-06) per-step current drawdown ratio max(0, (peak − equity) / peak). Stateful kernel output (NOT cross-fold persistent); FoldReset sentinel 0 so the new fold's first `launch_sp15_dd_state` writes the new fold's true value (no DD at fold start by definition). Per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3.",
            },
            RegistryEntry {
                name: "sp15_dd_max",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_MAX_INDEX=402] — SP15 Phase 1.3 (2026-05-06) running max of DD_CURRENT across the current fold. Stateful kernel output; FoldReset sentinel 0 since each fold's max-DD is independent — cross-fold persistence would silently drag the calmar denominator floor between folds and break the invariant that calmar reports the worst draw-down OF THIS FOLD. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3.",
            },
            RegistryEntry {
                name: "sp15_dd_recovery_bars",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_RECOVERY_BARS_INDEX=403] — SP15 Phase 1.3 (2026-05-06) bars since last new high-water mark in the current fold. Stateful counter; FoldReset sentinel 0 (new fold = fresh recovery counter; the kernel zeros this slot in-flight whenever a new peak fires, but cold-start of the new fold also requires the slot to be 0 so the very first below-peak step starts the counter from 0 → 1). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3.",
            },
            RegistryEntry {
                name: "sp15_dd_persistence",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_PERSISTENCE_INDEX=404] — SP15 Phase 1.3 (2026-05-06) twin counter to DD_RECOVERY_BARS in this phase (split-lifetime semantics may diverge in a later phase, e.g. recovery resets at any fresh peak while persistence resets only above a hysteresis band). FoldReset sentinel 0 same rationale as DD_RECOVERY_BARS. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3.",
            },
            RegistryEntry {
                name: "sp15_calmar",
                category: ResetCategory::FoldReset,
                description: "ISV[CALMAR_INDEX=405] — SP15 Phase 1.3 (2026-05-06) floored max-DD denominator for the host composer's `calmar = mean_pnl / value-here`. Kernel writes `max(dd_max, 1e-4)` so the floor eliminates the saturation-at-100 artifact seen in train-dd4xl HEALTH_DIAG when max-DD ≈ 0. FoldReset sentinel 1e-4 (the SAME floor value, NOT 0) so the very first calmar division at fold start uses the floor — sentinel 0 would yield ±inf and immediately re-trip the saturation guard before the first kernel launch overwrites the slot. Per `feedback_isv_for_adaptive_bounds.md` (1e-4 is an Invariant-1 anchor — the floor value is fixed structural protection, not an adaptive EMA). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3.",
            },
            RegistryEntry {
                name: "sp15_dd_pct",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_PCT_INDEX=406] — SP15 Phase 1.3 (2026-05-06) `clip(current_dd / max(dd_budget, 1e-4), 0, 1)` ∈ [0, 1]. Phase 1.3.b-followup (2026-05-07): now mean-aggregated across envs by `dd_state_reduce_kernel` from the per-env tile (the per-(env, slot) DD context is read directly by `compute_sp15_final_reward_kernel` from `sp15_dd_state_per_env[env*6 + 5]`; this scalar is the HEALTH_DIAG diagnostic summary). Stateful kernel output; FoldReset sentinel 0 (cold-start at fold boundary; the reduction kernel overwrites with the true mean on the new fold's first launch). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3.",
            },
            // ── SP15 Phase 1.3.b-followup (2026-05-07): per-env DD redesign ──
            //   - sp15_dd_state_per_env (NOT an ISV slot — `[alloc_episodes
            //     × 6]` mapped-pinned tile on the experience collector):
            //     FoldReset sentinel 0 across all `n_envs * 6` slots — every
            //     stateful field (running max + recovery counter +
            //     persistence counter per env) bootstraps from zero on the
            //     new fold's first kernel launch. Reset path:
            //     `host_slice_mut().fill(0.0)` (allowed under
            //     `feedback_no_htod_htoh_only_mapped_pinned.md`'s allowed-
            //     write rule, NOT a host-side compute). Mirrors the
            //     `sp15_alpha_warm_count` / `sp15_dd_trajectory_prev_dd`
            //     non-ISV mapped-pinned reset pattern. Without this reset
            //     the new fold's first reward shaping would inherit the
            //     previous fold's running max + counters, which would
            //     silently bias the per-env DD context.
            //   - DD_PERSISTENCE_MAX_INDEX=443: max-aggregate of per-env
            //     DD_PERSISTENCE across all envs, written by
            //     `dd_state_reduce_kernel`. Read by
            //     `plasticity_injection_kernel` so the global advantage-
            //     head reset fires when ANY env's persistence exceeds the
            //     threshold (one set of advantage weights → global firing
            //     semantics → max-aggregate is the only correct rule when
            //     ANY env exceeding the threshold should arm the gate;
            //     mean-aggregate would silently gate the trigger when only
            //     a fraction of envs are in long DD). FoldReset sentinel 0
            //     same rationale as DD_PERSISTENCE_INDEX (a fresh fold
            //     starts with the per-env counters at 0; the reduction
            //     max is therefore 0 until the first per-env DD-step
            //     fires).
            // Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3
            // post-Phase-1.3.b-followup audit doc entry.
            RegistryEntry {
                name: "sp15_dd_state_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.sp15_dd_state_per_env [alloc_episodes * 6] f32 mapped-pinned per-env DD state tile — SP15 Phase 1.3.b-followup (2026-05-07) per-env redesign of the DD state machine (Path A → Path B migration). Layout: tile[env*6 + 0..6] = [DD_CURRENT, DD_MAX, DD_RECOVERY_BARS, DD_PERSISTENCE, CALMAR floor, DD_PCT] for env in [0, alloc_episodes). Read-modify-written by `dd_state_kernel` (per-env grid, one thread per env, stateful per-bar walk). Read by `dd_state_reduce_kernel` (mean across envs → ISV slots [401..407); max(persistence) → ISV[DD_PERSISTENCE_MAX_INDEX=443]). Read by `compute_sp15_final_reward_kernel` per-(i,t) via `env_id = (idx % (N*L)) / L`. FoldReset sentinel 0 across all `n_envs * 6` slots — every stateful field (running max, recovery + persistence counters) bootstraps from zero on the new fold's first kernel launch (same rationale as the individual ISV scalars in the original Phase 1.3 reset arms). Reset path: `host_slice_mut().fill(0.0)` mirrors the `sp15_alpha_warm_count` / `sp15_dd_trajectory_prev_dd` non-ISV mapped-pinned reset pattern. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3 + docs/dqn-wire-up-audit.md Phase 1.3.b-followup entry.",
            },
            RegistryEntry {
                name: "sp15_dd_persistence_max",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_PERSISTENCE_MAX_INDEX=443] — SP15 Phase 1.3.b-followup (2026-05-07) max-aggregate of per-env DD_PERSISTENCE across all envs, written by `dd_state_reduce_kernel` from the per-env tile. Read by `plasticity_injection_kernel` so the global advantage-head reset fires when ANY env's persistence exceeds the threshold — one set of advantage weights → global firing semantics → max-aggregate is the only correct rule (mean-aggregate would silently gate the trigger when only a fraction of envs are in long DD). Stateful kernel output; FoldReset sentinel 0 (a fresh fold starts with all per-env persistence counters at 0; the max-aggregate is therefore 0 until the first per-env DD-step fires the counter). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §6.3 + docs/dqn-wire-up-audit.md Phase 1.3.b-followup entry.",
            },
            // ── SP15 Phase 3.1 (2026-05-06): r_quality + r_discipline split ───
            // Three ISV slots [417..420) + one mapped-pinned scratch buffer
            // (`sp15_alpha_warm_count`):
            //   - ALPHA_SPLIT_INDEX=417: Invariant-1 sentinel anchor (NOT a
            //     stateful EMA). Constructor-seeded to 0.5 per spec §8.2 (3.1)
            //     post-amendment-2 fix; FoldReset rewrites the same 0.5 anchor
            //     so the composer's cold-start absorber re-engages on each new
            //     fold (the warm-count goes back to 0; the producer kernel
            //     becomes a no-op until `*warm_count >= N_WARM=100` again).
            //     Per `feedback_isv_for_adaptive_bounds.md` — the structural
            //     0.5 anchor is the cold-start absorber, the runtime value is
            //     signal-driven once warmup completes.
            //   - GRAD_NORM_QUALITY_INDEX=418: stateful EMA of the r_quality
            //     gradient L2 norm. FoldReset sentinel 0 so Pearl A
            //     bootstraps from the new fold's first observation per
            //     `pearl_first_observation_bootstrap.md`.
            //   - GRAD_NORM_DISCIPLINE_INDEX=419: stateful EMA of the
            //     r_discipline gradient L2 norm. FoldReset sentinel 0 same
            //     rationale as quality.
            //   - sp15_alpha_warm_count (NOT an ISV slot — single-element
            //     mapped-pinned scratch buffer on the trainer struct):
            //     FoldReset sentinel 0.0 via `host_slice_mut().fill(0.0)`
            //     so the new fold's first composer launch re-enters the
            //     warm-up window from step 0 and the producer-kernel gate
            //     re-engages. Mirrors the `sp11_novelty_hash` pattern of
            //     resetting a non-ISV mapped-pinned buffer at fold boundary.
            // Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.1).
            RegistryEntry {
                name: "sp15_alpha_split",
                category: ResetCategory::FoldReset,
                description: "ISV[ALPHA_SPLIT_INDEX=417] — SP15 Phase 3.1 (2026-05-06) blend coefficient for `r_total = α × r_quality + (1 − α) × r_discipline`. Constant Invariant-1 anchor (0.5) per `feedback_isv_for_adaptive_bounds.md` — NOT a stateful EMA. Constructor-seeded to 0.5; FoldReset rewrites the same anchor so the composer's cold-start absorber re-engages on each new fold (per spec §8.2 (3.1) post-amendment-2 fix: deriving α from `grad_norm_q / (grad_norm_q + grad_norm_d + ε)` at boot would produce 0/0=0 from zero grad-norm EMAs). The companion `alpha_split_producer_kernel` is gated on `sp15_alpha_warm_count` and stays a silent no-op until `*warm_count >= N_WARM=100`, at which point it activates and writes the formula's clamped output here on each step. Per-fold ISV refit may overwrite this in later phases. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.1).",
            },
            RegistryEntry {
                name: "sp15_grad_norm_quality",
                category: ResetCategory::FoldReset,
                description: "ISV[GRAD_NORM_QUALITY_INDEX=418] — SP15 Phase 3.1 (2026-05-06) stateful EMA of the r_quality gradient L2 norm. Read by `alpha_split_producer_kernel` (post-warmup) to compute `α = grad_norm_q / (grad_norm_q + grad_norm_d + ε)`. FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first observation per `pearl_first_observation_bootstrap.md` (also drives the warm-count gate: `alpha_split_producer_kernel` will re-enter no-op state at fold boundary because the companion `sp15_alpha_warm_count` resets in the same arm cluster). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.1).",
            },
            RegistryEntry {
                name: "sp15_grad_norm_discipline",
                category: ResetCategory::FoldReset,
                description: "ISV[GRAD_NORM_DISCIPLINE_INDEX=419] — SP15 Phase 3.1 (2026-05-06) stateful EMA of the r_discipline gradient L2 norm. Read by `alpha_split_producer_kernel` (post-warmup) as the denominator partner of `sp15_grad_norm_quality`. FoldReset sentinel 0 same rationale as quality. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.1).",
            },
            RegistryEntry {
                name: "sp15_alpha_warm_count",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.sp15_alpha_warm_count [1] f32 mapped-pinned scratch buffer — SP15 Phase 3.1 (2026-05-06) warm-up counter for the r_quality + r_discipline split composer (per spec §8.2 (3.1) post-amendment-2 fix). Initialised to 0.0 in the constructor; incremented by 1 each step inside `r_quality_discipline_split_kernel`; once `*count >= N_WARM=100` the composer stops overriding α to 0.5 and `alpha_split_producer_kernel` activates from no-op state. FoldReset sentinel 0.0 via `host_slice_mut().fill(0.0)` (mirrors the `sp11_novelty_hash` pattern of resetting a non-ISV mapped-pinned buffer at fold boundary) — the new fold's first composer launch must re-enter the warm-up window from step 0 so the cold-start absorber holds α at 0.5 long enough for the new fold's grad-norm EMAs to accumulate ≥100 non-zero observations before the producer kernel takes over. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.1).",
            },
            // SP15 Phase 3.3 (2026-05-06) — quadratic DD penalty anchors
            // (per spec §8.2 (3.3)). `penalty = λ_dd × max(0, dd_current −
            // dd_threshold)²`. dd_current=ISV[401] is reset by the
            // existing `sp15_dd_current` Phase 1.3 entry; the three slots
            // owned by this phase are reset here.
            RegistryEntry {
                name: "sp15_lambda_dd",
                category: ResetCategory::FoldReset,
                description: "ISV[LAMBDA_DD_INDEX=420] — SP15 Phase 3.3 (2026-05-06) penalty strength multiplier for the quadratic DD penalty (per spec §8.2 (3.3)). FoldReset rewrites the structural cold-start anchor 1.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from the gradient-balance producer in the follow-up commit; the 1.0 anchor re-engages on each new fold so the cold-start absorber holds the penalty at a finite scale until the new fold's grad-norm EMA accumulates enough observations to drive the producer. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.3).",
            },
            RegistryEntry {
                name: "sp15_dd_threshold",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_THRESHOLD_INDEX=421] — SP15 Phase 3.3 (2026-05-06) drawdown trigger threshold for the quadratic DD penalty (per spec §8.2 (3.3)). FoldReset rewrites the structural Invariant-1 anchor 0.05 (5% drawdown trigger) per `feedback_isv_for_adaptive_bounds.md` — fixed structural anchor, NOT a stateful EMA. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.3).",
            },
            RegistryEntry {
                name: "sp15_dd_penalty_grad_norm",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_PENALTY_GRAD_NORM_INDEX=422] — SP15 Phase 3.3 (2026-05-06) stateful EMA of the DD penalty gradient L2 norm. Read by the follow-up λ_dd grad-balance producer kernel (deferred per `feedback_no_partial_refactor.md`); FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first observation per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.3).",
            },
            // SP15 Phase 3.4 (2026-05-06) — regret-signal anchors
            // (per spec §8.2 (3.4)). `regret_bar = ideal_pnl_missed -
            // cost_t` when policy held AND ideal trade past
            // cost+trail; EMA tracked at REGRET_EMA via
            // first-observation bootstrap + exponential decay α=0.05
            // (Wiener-α adaptive swap = follow-up). The reward composer
            // subtracts `LAMBDA_REGRET × REGRET_EMA` from r_discipline
            // at the deferred follow-up consumer site.
            RegistryEntry {
                name: "sp15_regret_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[REGRET_EMA_INDEX=423] — SP15 Phase 3.4 (2026-05-06) stateful EMA of the regret/opportunity-cost signal (per spec §8.2 (3.4)). FoldReset sentinel 0 so the kernel's first-observation bootstrap (per `pearl_first_observation_bootstrap.md`) re-engages on the new fold's first non-zero `regret_bar` observation. Read by the follow-up reward composer that subtracts `LAMBDA_REGRET × REGRET_EMA` from r_discipline (deferred per `feedback_no_partial_refactor.md`). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.4).",
            },
            RegistryEntry {
                name: "sp15_lambda_regret",
                category: ResetCategory::FoldReset,
                description: "ISV[LAMBDA_REGRET_INDEX=424] — SP15 Phase 3.4 (2026-05-06) regret-penalty strength multiplier (per spec §8.2 (3.4)). FoldReset rewrites the structural cold-start anchor 1.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up grad-balance producer kernel; the 1.0 anchor re-engages on each new fold so the cold-start absorber holds the regret penalty at a finite scale until the new fold's `REGRET_GRAD_NORM` EMA accumulates enough observations to drive the producer. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.4).",
            },
            RegistryEntry {
                name: "sp15_regret_grad_norm",
                category: ResetCategory::FoldReset,
                description: "ISV[REGRET_GRAD_NORM_INDEX=425] — SP15 Phase 3.4 (2026-05-06) stateful EMA of the regret-penalty gradient L2 norm. Read by the follow-up λ_regret grad-balance producer kernel (deferred per `feedback_no_partial_refactor.md`); FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first observation per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.4).",
            },
            // SP15 Phase 3.5 (2026-05-06) — confidence-aware Hold-floor
            // anchors (per spec §8.2 (3.5) post-amendment-2 fix).
            // `hold_floor = α × σ(k × (entropy − ε₀))` — action-selection
            // level (NOT reward shaping). The follow-up consumer adds
            // `hold_floor` to Q_hold pre-argmax/Thompson selection so
            // Hold becomes uncertainty expression rather than the
            // distributional default. The signal-driven producers that
            // overwrite α / k / ε₀ from rolling 95th percentile of
            // |Q_dir| (NOT running max — outlier-ratchet vulnerable per
            // spec second-review #6), running variance of entropy, and
            // 75th percentile of running entropy distribution are
            // documented Phase 3.5 follow-up sub-tasks; FoldReset
            // rewrites the structural cold-start anchors so the
            // absorbers re-engage on each new fold per
            // `feedback_isv_for_adaptive_bounds.md`. ENTROPY_DIST_REF
            // is the running 75th-percentile reference the deferred ε₀
            // producer reads — Pearl A sentinel 0.
            RegistryEntry {
                name: "sp15_hold_floor_alpha",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_FLOOR_ALPHA_INDEX=426] — SP15 Phase 3.5 (2026-05-06) confidence-aware Hold-floor scale factor (per spec §8.2 (3.5) post-amendment-2 fix). FoldReset rewrites the structural cold-start anchor 0.5 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer kernel that tracks the rolling 95th percentile of |Q_dir| (NOT running max — outlier-ratchet vulnerable per spec second-review #6); the 0.5 anchor re-engages on each new fold so the cold-start absorber holds α at a finite scale until the producer accumulates observations. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.5).",
            },
            RegistryEntry {
                name: "sp15_hold_floor_k",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_FLOOR_K_INDEX=427] — SP15 Phase 3.5 (2026-05-06) confidence-aware Hold-floor sigmoid steepness (per spec §8.2 (3.5)). FoldReset rewrites the structural cold-start anchor 10.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer kernel that tracks the running variance of entropy; the 10.0 anchor re-engages on each new fold. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.5).",
            },
            RegistryEntry {
                name: "sp15_hold_floor_eps0",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_FLOOR_EPS0_INDEX=428] — SP15 Phase 3.5 (2026-05-06) confidence-aware Hold-floor entropy threshold ε₀ (per spec §8.2 (3.5)). FoldReset rewrites the structural cold-start anchor 1.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer kernel that tracks the 75th percentile of the running entropy distribution (`ENTROPY_DIST_REF_INDEX=429`); the 1.0 anchor re-engages on each new fold. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.5).",
            },
            RegistryEntry {
                name: "sp15_entropy_dist_ref",
                category: ResetCategory::FoldReset,
                description: "ISV[ENTROPY_DIST_REF_INDEX=429] — SP15 Phase 3.5 (2026-05-06) running 75th-percentile reference for the entropy distribution. Read by the follow-up ε₀ producer kernel (deferred per `feedback_no_partial_refactor.md`); FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first non-zero observation per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §8.2 (3.5).",
            },
            // SP15 Phase 3.5.2 (2026-05-06) — asymmetric reward under DD
            // anchors (per spec §9.2 (3.5.2)). For gains
            // `r_adjusted = r × (1 + λ × dd_pct)`; for losses unchanged.
            // Applied BEFORE the SP12 v3 NEG/POS reward cap clamp.
            // Asymmetric gain-only multiplier preserves loss aversion
            // through the SP12-cap pipeline per
            // `pearl_audit_unboundedness_for_implicit_asymmetry` (Phase
            // 3.3 restored asymmetry on the drawdown-axis penalty side;
            // 3.5.2 closes the recovery half of the same axis).
            // λ_DD_ASYMMETRY is a structural cold-start anchor — runtime
            // value is signal-driven from the follow-up λ producer
            // reading the running variance of dd_pct (DD_DIST_VAR slot
            // 432). R_GAIN_DD_BOOST is the diagnostic slot recording the
            // most-recent boost factor (1.0 = no-op). DD_DIST_VAR is a
            // stateful EMA — Pearl A sentinel 0.
            RegistryEntry {
                name: "sp15_dd_asymmetry_lambda",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_ASYMMETRY_LAMBDA_INDEX=430] — SP15 Phase 3.5.2 (2026-05-06) asymmetric DD-recovery reward multiplier coefficient (per spec §9.2 (3.5.2)). FoldReset rewrites the structural cold-start anchor 0.5 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer kernel that tracks the running variance of dd_pct (`DD_DIST_VAR_INDEX=432`); the 0.5 anchor re-engages on each new fold so the cold-start absorber holds λ at a finite scale until the producer accumulates observations. The asymmetric gain-only multiplier preserves loss aversion through the SP12-cap pipeline per `pearl_audit_unboundedness_for_implicit_asymmetry`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.2).",
            },
            RegistryEntry {
                name: "sp15_r_gain_dd_boost",
                category: ResetCategory::FoldReset,
                description: "ISV[R_GAIN_DD_BOOST_INDEX=431] — SP15 Phase 3.5.2 (2026-05-06) diagnostic slot recording the most-recent boost factor applied by `dd_asymmetric_reward_kernel`. 1.0 ⇒ no-op (loss side, or dd_pct=0 at ATH); >1.0 ⇒ gain × DD-recovery boost actually fired. Read by HEALTH_DIAG in the consumer-wiring follow-up. FoldReset rewrites the 1.0 sentinel so the first HEALTH_DIAG emission on a new fold (before any kernel launch) reads as 'no boost yet' rather than carrying the previous fold's last-recorded value. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.2).",
            },
            RegistryEntry {
                name: "sp15_dd_dist_var",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_DIST_VAR_INDEX=432] — SP15 Phase 3.5.2 (2026-05-06) running variance of dd_pct, read by the follow-up λ producer kernel (deferred per `feedback_no_partial_refactor.md`); FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first non-zero observation per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.2).",
            },
            // SP15 Phase 3.5.3 (2026-05-06) — cooldown gate anchors
            // (per spec §9.2 (3.5.3)). After K consecutive losing
            // trades, force Hold for M bars. K and M are ISV-tracked
            // (slots 433/434); initial sentinels K=5, M=20 hardcoded
            // in the trainer constructor (ISV-driven K via
            // `MEDIAN_STREAK_LENGTH_INDEX=442` producer using two-heap
            // median tracking is a documented Phase 3.5.3 follow-up
            // sub-task per `feedback_isv_for_adaptive_bounds.md`;
            // ISV-driven M from vol_normalizer time-to-mean-reversion
            // is a parallel follow-up). COOLDOWN_BARS_REMAINING is
            // counter state — FoldReset sentinel 0 so the new fold
            // starts with no active cooldown. MEDIAN_STREAK_LENGTH is
            // a stateful EMA — FoldReset sentinel 0 (Pearl A) so the
            // deferred producer's first-observation replacement fires
            // on the new fold's first non-zero streak observation.
            RegistryEntry {
                name: "sp15_cooldown_k_threshold",
                category: ResetCategory::FoldReset,
                description: "ISV[COOLDOWN_K_THRESHOLD_INDEX=433] — SP15 Phase 3.5.3 (2026-05-06) cooldown gate threshold K (consecutive-loss count that triggers the force-Hold gate). FoldReset rewrites the structural cold-start anchor 5.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer kernel reading the rolling median of consecutive-loss streak lengths via the two-heap algorithm (`MEDIAN_STREAK_LENGTH_INDEX=442`); the 5.0 anchor re-engages on each new fold so the cold-start absorber holds K at a finite scale until the producer accumulates observations. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.3).",
            },
            RegistryEntry {
                name: "sp15_cooldown_m_bars",
                category: ResetCategory::FoldReset,
                description: "ISV[COOLDOWN_M_BARS_INDEX=434] — SP15 Phase 3.5.3 (2026-05-06) cooldown gate duration M (number of bars to force Hold after the gate trips). FoldReset rewrites the structural cold-start anchor 20.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer reading the vol_normalizer time-to-mean-reversion estimate; the 20.0 anchor re-engages on each new fold. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.3).",
            },
            RegistryEntry {
                name: "sp15_cooldown_bars_remaining",
                category: ResetCategory::FoldReset,
                description: "ISV[COOLDOWN_BARS_REMAINING_INDEX=435] — SP15 Phase 3.5.3 (2026-05-06) cooldown gate remaining-bars counter (part of state so the model can reason about it). FoldReset sentinel 0 so the new fold starts with no active cooldown — leftover state from the previous fold would force Hold during the new fold's warmup, contaminating the cold-start. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.3).",
            },
            RegistryEntry {
                name: "sp15_median_streak_length",
                category: ResetCategory::FoldReset,
                description: "ISV[MEDIAN_STREAK_LENGTH_INDEX=442] — SP15 Phase 3.5.3 (2026-05-06) running median of consecutive-loss streak lengths, read by the follow-up ISV-driven K producer (deferred per `feedback_no_partial_refactor.md` — two-heap median algorithm); FoldReset sentinel 0 so Pearl A bootstraps from the new fold's first non-zero observation per `pearl_first_observation_bootstrap.md`. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.3).",
            },
            // SP15 Phase 3.5.3 (2026-05-06) — cooldown gate streak
            // counter scratch buffer (non-ISV mapped-pinned). Mirrors
            // the Phase 3.1 `sp15_alpha_warm_count` non-ISV
            // mapped-pinned reset pattern. Reset to 0.0 via
            // `host_slice_mut().fill(0.0)` (allowed under
            // `feedback_no_htod_htoh_only_mapped_pinned.md`'s
            // allowed-write rule, NOT a host-side compute) — the new
            // fold's first cooldown_kernel launch must see a fresh
            // streak counter so a partially-accumulated streak from
            // the previous fold cannot trip the gate during the new
            // fold's warmup.
            RegistryEntry {
                name: "sp15_cooldown_consecutive_losses",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.sp15_cooldown_consecutive_losses [1] f32 mapped-pinned scratch buffer — SP15 Phase 3.5.3 (2026-05-06) consecutive-loss streak counter for the cooldown gate (per spec §9.2 (3.5.3) post-amendment-2 fix). Initialised to 0.0 in the constructor; read-modify-written by `cooldown_kernel`: `+= 1.0f` on trade-close losses, `= 0.0f` on trade-close wins (streak broken), untouched on non-trade-close bars. FoldReset sentinel 0.0 via `host_slice_mut().fill(0.0)` (mirrors the Phase 3.1 `sp15_alpha_warm_count` pattern of resetting a non-ISV mapped-pinned buffer at fold boundary) — the new fold's first cooldown_kernel launch must see a fresh streak counter so a partially-accumulated streak from the previous fold cannot trip the gate during the new fold's warmup. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.3).",
            },
            // SP15 Phase 3.5.4 (2026-05-06): plasticity injection trigger
            // + warm-up tracker anchors (per spec §9.2 (3.5.4)
            // post-amendment-2 fix). TWO-STEP recovery — fire when
            // DD_PERSISTENCE > threshold AND fired_flag == 0 → set
            // fired flag, set warm-bars counter to M_warm (default
            // 200), [DEFERRED: Kaiming-He weight reset]; per-bar
            // warm-bars decrement; consumer-wiring follow-up reads
            // max(COOLDOWN_BARS_REMAINING, PLASTICITY_WARM_BARS_REMAINING)
            // and forces Hold while > 0. PLASTICITY_FIRED_THIS_FOLD
            // resets to 0.0 at fold boundary — this is the load-
            // bearing semantics for the "once per fold" debounce: the
            // gate fires at most once per fold, then re-arms on the
            // next fold. PLASTICITY_PERSISTENCE_THRESHOLD is a
            // structural cold-start anchor per
            // `feedback_isv_for_adaptive_bounds.md` (runtime value
            // signal-driven from a follow-up producer reading the
            // running mean of dd_persistence_bars). PLASTICITY_WARM_
            // BARS_REMAINING is counter state — FoldReset sentinel 0
            // so the new fold starts with no active warm-up.
            RegistryEntry {
                name: "sp15_plasticity_fired_this_fold",
                category: ResetCategory::FoldReset,
                description: "ISV[PLASTICITY_FIRED_THIS_FOLD_INDEX=436] — SP15 Phase 3.5.4 (2026-05-06) plasticity injection debounce flag. Set to 1.0 by `plasticity_injection_kernel` when DD_PERSISTENCE crosses the threshold (gate fires at most once per fold). FoldReset sentinel 0.0 — the load-bearing semantics for the 'once per fold' debounce: resetting to 0 at fold boundary re-arms the gate so it can fire again on the next fold's first persistence-threshold crossing. Without this reset, after the gate fires in fold N it would stay armed forever and never fire again across folds N+1..M, defeating the per-fold recovery semantic. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.4).",
            },
            RegistryEntry {
                name: "sp15_plasticity_persistence_threshold",
                category: ResetCategory::FoldReset,
                description: "ISV[PLASTICITY_PERSISTENCE_THRESHOLD_INDEX=437] — SP15 Phase 3.5.4 (2026-05-06) plasticity injection trigger threshold (number of consecutive bars in drawdown that triggers the gate). FoldReset rewrites the structural cold-start anchor 100.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer reading the running mean of dd_persistence_bars (so the threshold tracks the typical drawdown duration distribution); the 100.0 anchor re-engages on each new fold so the cold-start absorber holds the threshold at a finite scale until the producer accumulates observations. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.4).",
            },
            RegistryEntry {
                name: "sp15_plasticity_warm_bars_remaining",
                category: ResetCategory::FoldReset,
                description: "ISV[PLASTICITY_WARM_BARS_REMAINING_INDEX=438] — SP15 Phase 3.5.4 (2026-05-06) plasticity injection warm-up counter (number of bars remaining where action-selection forces Hold post-fire via the OR-gate `max(COOLDOWN_BARS_REMAINING, PLASTICITY_WARM_BARS_REMAINING)`). Set to M_warm (default 200) by `plasticity_injection_kernel` on fire; decremented per bar. FoldReset sentinel 0.0 so the new fold starts with no active warm-up — leftover state from the previous fold would force Hold during the new fold's warmup, contaminating the cold-start (mirrors `sp15_cooldown_bars_remaining` semantics). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.4).",
            },
            // SP15 Phase 3.5.5 (2026-05-06) — recovery curriculum in
            // PER: per-step DD_TRAJECTORY_DECREASING proxy (per spec
            // §9.2 (3.5.5) post-amendment-2 fix). Replaces non-existent
            // episode-level metadata with a per-bar boolean from the
            // dd_pct trajectory. PER sampling consumer (deferred
            // follow-up): `sampling_weight = base × (1 +
            // RECOVERY_OVERSAMPLE_WEIGHT × DD_TRAJECTORY_DECREASING)`.
            // DD_TRAJECTORY_FLOOR is ISV-driven (25th percentile of
            // running dd_pct distribution; producer is a follow-up
            // sub-task per `feedback_isv_for_adaptive_bounds.md`);
            // RECOVERY_OVERSAMPLE_WEIGHT is also ISV-driven (proportional
            // to current dd_pct — more DD now → higher weight; producer
            // is the same follow-up sub-task). DD_TRAJECTORY_DECREASING
            // is the per-bar output — FoldReset sentinel 0 so the new
            // fold starts with no carry-over signal. Both anchors
            // (FLOOR=0.02, OVERSAMPLE=2.0) rewrite at fold boundary so
            // the cold-start absorbers re-engage on each new fold per
            // phase precedent.
            RegistryEntry {
                name: "sp15_dd_trajectory_decreasing",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_TRAJECTORY_DECREASING_INDEX=439] — SP15 Phase 3.5.5 (2026-05-06) recovery-curriculum per-step proxy. Per-bar boolean (0.0/1.0) computed by `dd_trajectory_decreasing_kernel`: 1.0 iff `dd_pct(t) < dd_pct(t-1) AND dd_pct(t-1) > DD_TRAJECTORY_FLOOR`. Read by the deferred PER sampling consumer (`sampling_weight = base × (1 + RECOVERY_OVERSAMPLE_WEIGHT × DD_TRAJECTORY_DECREASING)`). FoldReset sentinel 0 so the new fold starts with no carry-over signal — leftover '1.0' from the previous fold's last bar would over-weight the new fold's first replay-buffer entry. The companion `sp15_dd_trajectory_prev_dd` scratch buffer reset in the same arm cluster ensures the kernel's persistent prev_dd_pct cannot trigger a false recovery on the new fold's first call (mirrors the Phase 3.5.3 `sp15_cooldown_consecutive_losses` reset pattern). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.5).",
            },
            RegistryEntry {
                name: "sp15_recovery_oversample_weight",
                category: ResetCategory::FoldReset,
                description: "ISV[RECOVERY_OVERSAMPLE_WEIGHT_INDEX=440] — SP15 Phase 3.5.5 (2026-05-06) PER sampling oversample weight for recovery transitions. FoldReset rewrites the structural cold-start anchor 2.0 per `feedback_isv_for_adaptive_bounds.md` — the runtime value will be signal-driven from a follow-up producer kernel reading the current dd_pct (more DD now → higher weight for recovery samples so the agent learns recovery dynamics over typical 'average-DD' Bellman noise); the 2.0 anchor re-engages on each new fold so the cold-start absorber holds the weight at a finite scale until the producer accumulates observations. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.5).",
            },
            RegistryEntry {
                name: "sp15_dd_trajectory_floor",
                category: ResetCategory::FoldReset,
                description: "ISV[DD_TRAJECTORY_FLOOR_INDEX=441] — SP15 Phase 3.5.5 (2026-05-06) non-trivial-drawdown floor for the DD_TRAJECTORY_DECREASING gate (`dd_prev > floor` term). FoldReset rewrites the structural cold-start anchor 0.02 per `feedback_isv_for_adaptive_bounds.md` — replaces the hardcoded 0.02 floor from the original spec draft; the runtime value will be signal-driven from a follow-up producer reading the rolling 25th percentile of the dd_pct distribution (ensures the floor tracks the typical small-drawdown threshold instead of being decoupled from the actual dd_pct scale). The 0.02 anchor re-engages on each new fold so the cold-start absorber holds the floor at a finite scale until the producer accumulates observations. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.5).",
            },
            // SP15 Phase 3.5.5 (2026-05-06) → Phase 1.3.b-followup-B
            // (2026-05-07): the trainer-owned `[1]` scratch buffer
            // `sp15_dd_trajectory_prev_dd` was reshaped to two
            // per-env tiles owned by `GpuExperienceCollector`:
            //   * `sp15_dd_trajectory_per_env` (`[alloc_episodes]`
            //     mapped-pinned tile on the collector): per-env
            //     DD_TRAJECTORY_DECREASING output. Read by
            //     `per_insert_pa` per-transition via insert-time
            //     `env_id = (j % (n_envs * lookback)) / lookback` so
            //     each inserted transition's recovery boost reflects
            //     ITS env's recovery context (NOT the most-recent
            //     ISV[439] writer's, which was the Wave 4.3 limitation).
            //   * `sp15_dd_trajectory_prev_dd_per_env` (`[alloc_episodes]`
            //     mapped-pinned tile on the collector): per-env
            //     persistent previous-bar dd_pct scratch (replaces
            //     the deleted trainer-owned `[1]` scalar).
            // Both tiles FoldReset sentinel 0 across all
            // `alloc_episodes` slots — every stateful field
            // bootstraps from zero on the new fold's first kernel
            // launch (mirrors the `sp15_dd_state_per_env`
            // collector-owned reset pattern). Reset path:
            // `host_slice_mut().fill(0.0)` (allowed under
            // `feedback_no_htod_htoh_only_mapped_pinned.md`'s
            // allowed-write rule, NOT a host-side compute).
            RegistryEntry {
                name: "sp15_dd_trajectory_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.sp15_dd_trajectory_per_env [alloc_episodes] f32 mapped-pinned per-env DD_TRAJECTORY_DECREASING output tile — SP15 Phase 1.3.b-followup-B (2026-05-07) per-(env, t) redesign of the recovery-curriculum trajectory output (Wave 4.3 → followup-B migration). Layout: tile[env] = 1.0 iff env's `dd_pct(t) < dd_pct(t-1) AND dd_pct(t-1) > DD_TRAJECTORY_FLOOR`, else 0.0, for env in [0, alloc_episodes). Written by `dd_trajectory_decreasing_kernel` (per-env grid, one thread per env). Read by `per_insert_pa` per-transition via insert-time `env_id = (j % (n_envs * lookback)) / lookback` so each transition's recovery oversample boost reflects ITS env's recovery context — fixes the Wave 4.3 statistical bias where ISV[DD_TRAJECTORY_DECREASING_INDEX=439] was read once per insert call and applied uniformly to all transitions in the batch. Read by `dd_state_reduce_kernel` for mean-aggregate into ISV[439] (HEALTH_DIAG diagnostic preservation; production reads the per-env tile directly). FoldReset sentinel 0 across all `alloc_episodes` slots — leftover '1.0' from the previous fold's last bar would over-weight the new fold's first replay-buffer entry. Reset path: `host_slice_mut().fill(0.0)` mirrors the `sp15_dd_state_per_env` / `sp15_dd_trajectory_prev_dd_per_env` collector-owned reset pattern. Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.5) + docs/dqn-wire-up-audit.md Phase 1.3.b-followup-B entry.",
            },
            RegistryEntry {
                name: "sp15_dd_trajectory_prev_dd_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.sp15_dd_trajectory_prev_dd_per_env [alloc_episodes] f32 mapped-pinned per-env persistent previous-bar dd_pct scratch — SP15 Phase 1.3.b-followup-B (2026-05-07) per-env redesign of the recovery-curriculum trajectory state (replaces the deleted trainer-owned `[1]` `sp15_dd_trajectory_prev_dd` from Phase 3.5.5 / Wave 4.3). Layout: tile[env] = previous bar's per-env dd_pct, for env in [0, alloc_episodes). Read-modify-written by `dd_trajectory_decreasing_kernel` (per-env grid: each env's thread reads its slot to compute trajectory direction, then advances to current per-env dd_pct so next call sees correct 'previous'). FoldReset sentinel 0.0 across all `alloc_episodes` slots — the new fold's first kernel launch must see prev=0.0 so the floor gate (`dd_prev > DD_TRAJECTORY_FLOOR=0.02` sentinel) evaluates to false and trajectory=0 on the bootstrap call, preventing a partially-accumulated dd_pct from the previous fold from triggering a false recovery on the new fold's first call. Reset path: `host_slice_mut().fill(0.0)` mirrors the `sp15_dd_state_per_env` / `sp15_dd_trajectory_per_env` collector-owned reset pattern (mirrors the Phase 3.1 `sp15_alpha_warm_count` and Phase 3.5.3 `sp15_cooldown_consecutive_losses` non-ISV mapped-pinned reset pattern at the function-level). Spec: docs/superpowers/specs/2026-05-06-sp15-honest-numbers.md §9.2 (3.5.5) + docs/dqn-wire-up-audit.md Phase 1.3.b-followup-B entry.",
            },
            // SP5 Task A1: Wiener-state companion reset. The wiener_state_buf
            // covers SP4 (SP4_PRODUCER_COUNT=71 producers × 3 = 213 floats) +
            // SP5 (SP5_PRODUCER_COUNT × 3 floats) = (71 + SP5_PRODUCER_COUNT) × 3
            // floats total. The SP5 triples start at offset 213 and span
            // SP5_PRODUCER_COUNT × 3 floats; the runtime constant lives in
            // `cuda_pipeline::sp5_isv_slots::SP5_PRODUCER_COUNT` and grows as
            // each subsequent SP adds producers (B1b fix-up landed slot 360 →
            // SP5_PRODUCER_COUNT=187 → buffer = 774 floats, SP5 block
            // [213..774)). Always derive sizes via the formula
            // `(71 + SP5_PRODUCER_COUNT) × 3` rather than committing the literal.
            // Both halves of the Pearl A sentinel contract must reset together per
            // `feedback_no_partial_refactor.md`.
            RegistryEntry {
                name: "sp5_wiener_state",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.wiener_state_buf SP5 block at offsets [SP4_PRODUCER_COUNT × 3 .. (SP4_PRODUCER_COUNT + SP5_PRODUCER_COUNT) × 3) = [213..(213 + SP5_PRODUCER_COUNT × 3)). The total buffer is sized via `SP5_WIENER_TOTAL_FLOATS = (SP4_PRODUCER_COUNT=71 + SP5_PRODUCER_COUNT) × 3` floats; refer to the runtime `SP5_PRODUCER_COUNT` (`cuda_pipeline::sp5_isv_slots`) for the current value rather than hardcoding a literal here — it grows on each SP follow-up (e.g. B1b fix-up landed slot 360 → SP5_PRODUCER_COUNT=187 → buffer=774 floats, SP5 block [213..774)). Each producer triple = {sample_var, diff_var, x_lag}. SP5 Pearl D Wiener-EMA state for ALL SP5 producers (Pearls 1, 2, 3, 4, 5, Layer D D1/D2/D3, SP7 T1, SP7 activation-flag fix, SP8 Fix 36, SP9 Kelly cold-start, SP10 eval Thompson temperature, SP11 reward-subsystem controller). Bulk write_bytes(0) at fold boundary covers the full wiener_state_buf [0..SP5_WIENER_TOTAL_FLOATS) so Pearl A's sentinel branch fires on the new fold's first producer launch. Pearl 6 (slots 280..286) does NOT use this buffer — Pearl 6 is cross-fold-persistent and uses in-kernel EWMA + cumulative-via-max(); the wiener slots [525..543) that Pearl 6 would map to under naive offset arithmetic (213 + (280-174)*3 = 525) are intentionally unused. Both SP4 and SP5 [non-Pearl-6] blocks reset atomically.",
            },
            // SP5 Task A6: Pearl 6 cross-fold-persistent Kelly cap signals.
            // ISV[280..286) are EXPLICITLY EXEMPT from this registry.
            // Adding fold-reset entries for these slots would defeat the entire
            // design purpose: these slots must survive across fold and window
            // boundaries to break the cold-start Kelly cap pathology.
            //
            // Investigation finding: portfolio_state has ResetCategory::WindowReset
            // (not FoldReset) — it resets at every WINDOW boundary. This makes the
            // cross-fold-persistent design even more critical: without Pearl 6, the
            // Kelly cold-start re-engages after every window, not just every fold.
            //
            // The pearl_6_kelly_kernel uses in-kernel slow EWMA (alpha=0.01) and
            // cumulative-via-max() for sample_count. No apply_pearls call; no wiener
            // state entries needed. ISV[280..286) are never zeroed by the fold-reset
            // path. This is the intended, documented behavior for Task A6.
            // SP5 Task A4: per-group Adam β1/β2/ε ISV slots (Pearl 4).
            // ISV[226..250) = 24 floats (8 groups × 3 hyperparams).
            // Pearl A sentinel 0 at fold boundary → first step fires first-observation
            // replacement (cosine_sim=0 → low-stability envelope midpoints).
            RegistryEntry {
                name: "sp5_adam_beta1",
                category: ResetCategory::FoldReset,
                description: "ISV[ADAM_BETA1_BASE=226..234) — per-group Adam β1 (gradient direction stability). Pearl 4 producer: cosine_sim→[0,1] → β1 = 0.85 + 0.10×stability ∈ [0.85, 0.95]. SP5 Pearl A sentinel 0 at fold boundary (Task A4).",
            },
            RegistryEntry {
                name: "sp5_adam_beta2",
                category: ResetCategory::FoldReset,
                description: "ISV[ADAM_BETA2_BASE=234..242) — per-group Adam β2 (gradient direction stability). Pearl 4 producer: cosine_sim→[0,1] → β2 = 0.99 + 0.0095×stability ∈ [0.99, 0.9995]. SP5 Pearl A sentinel 0 at fold boundary (Task A4).",
            },
            RegistryEntry {
                name: "sp5_adam_eps",
                category: ResetCategory::FoldReset,
                description: "ISV[ADAM_EPS_BASE=242..250) — per-group Adam ε (grad L2 norm scaled). Pearl 4 producer: ε = clamp(grad_norm×1e-7, 1e-10, 1e-6). SP5 Pearl A sentinel 0 at fold boundary (Task A4).",
            },
            RegistryEntry {
                name: "sp5_grad_prev_buf",
                category: ResetCategory::FoldReset,
                description: "GpuDqnTrainer.grad_prev_buf_per_group [total_params f32s] — previous-step gradient direction for cosine similarity computation (Pearl 4). Zero at fold boundary so the new fold's first grad_cosine_sim_update sees cosine_sim=0 (low-stability bootstrap) and Pearl A fires first-observation replacement (Task A4).",
            },
            // SP5 Task A5: per-branch IQN τ schedule (Pearl 5).
            // ISV[IQN_TAU_BASE=250..270) = 20 floats (4 branches × 5 quantiles).
            // Pearl A sentinel 0 at fold boundary → first step fires first-observation
            // replacement: zero skew → default symmetric schedule {0.05,0.25,0.5,0.75,0.95}.
            RegistryEntry {
                name: "sp5_iqn_tau",
                category: ResetCategory::FoldReset,
                description: "ISV[IQN_TAU_BASE=250..270) — per-branch IQN τ schedule (4 branches × 5 quantiles). SP5 Pearl A sentinel 0 at fold boundary so the new fold's first pearl_5_iqn_tau_update launch fires the first-observation replacement back to the symmetric default {0.05, 0.25, 0.5, 0.75, 0.95} at zero skew (Task A5).",
            },
            // SP5 Task A7: per-direction trail-stop distance (Pearl 8).
            // ISV[TRAIL_DIST_PER_DIR_BASE=270..274) = 4 floats (Short, Hold, Long, Flat).
            // Pearl A sentinel 0 at fold boundary → first pearl_8_trail_update launch
            // fires the first-observation replacement with the new fold's ATR value.
            RegistryEntry {
                name: "sp5_trail_dist_per_dir",
                category: ResetCategory::FoldReset,
                description: "ISV[TRAIL_DIST_PER_DIR_BASE=270..274) — per-direction trail-stop distance. Short[270] and Long[272]: atr_abs × 2.0; Hold[271] and Flat[273]: 1.0. SP5 Pearl A sentinel 0 at fold boundary so the first pearl_8_trail_update launch fires first-observation replacement with the new fold's ATR (Task A7).",
            },
            // SP5 Task A8: per-branch C51 num_atoms (Pearl 1-ext).
            // ISV[ATOM_NUM_ATOMS_BASE=274..278) = 4 floats (one per branch).
            // Pearl A sentinel 0 at fold boundary → first pearl_1_ext_num_atoms_update launch
            // fires the first-observation replacement with the new fold's v_half-derived count.
            RegistryEntry {
                name: "sp5_atom_num_atoms",
                category: ResetCategory::FoldReset,
                description: "ISV[ATOM_NUM_ATOMS_BASE=274..278) — per-branch C51 num_atoms (discrete {16, 32, 64} mapped from v_half thresholds, smoothed via Pearls A+D so transition-region values may be fractional; Layer B's atoms_update consumer rounds at consume time). SP5 Pearl A sentinel 0 at fold boundary triggers first-observation replacement (Task A8).",
            },
            // SP5 Layer D Task D1: PnL aggregation outputs (4 ISV slots).
            // ISV[286..290) — Layer D D1 PnL summary written by
            // pnl_aggregation_update producer kernel. NOT cross-fold persistent
            // (unlike Pearl 6's Kelly slots) — PnL aggregation is per-fold by
            // construction, so the standard Pearl A sentinel-bootstrap path
            // applies. Both halves of the contract reset together: ISV slot
            // zeroed AND wiener_state_buf SP5 block (offsets [213..555)) bulk
            // memset(0) at fold boundary covers the four new triples too,
            // so the new fold's first launcher fires Pearl A's first-observation
            // replacement (per `pearl_first_observation_bootstrap.md`).
            RegistryEntry {
                name: "sp5_pnl_aggregation",
                category: ResetCategory::FoldReset,
                description: "ISV[PNL_TOTAL_INDEX=286..PNL_MAX_DD_INDEX+1=290) — Layer D D1 PnL aggregation outputs (total/mean/population variance/max drawdown). SP5 Pearl A sentinel 0 at fold boundary so the new fold's first `launch_sp5_pnl_aggregation` fires the first-observation replacement (Task D1, 2026-05-02). Producer is `pnl_aggregation_kernel.cu`; consumer wires atomically in D4 (per `feedback_no_partial_refactor.md`). PnL aggregation is NOT cross-fold persistent — unlike Pearl 6's Kelly stats — so all four slots take the standard sentinel path. Wiener-state companion: bulk memset of the entire `wiener_state_buf[0..(71 + SP5_PRODUCER_COUNT) × 3)` at fold boundary covers the D1 triples at offsets [213+(286-174)*3 .. 213+(290-174)*3) = [549..561). reset_for_fold's existing bulk memset of the whole buffer length covers these triples atomically — no per-slot wiener entry is needed. Buffer size derives from SP5_PRODUCER_COUNT to avoid drift on subsequent SPs.",
            },
            // SP5 Layer D Task D2: Health composition outputs (4 ISV slots).
            // ISV[290..294) — Layer D D2 LearningHealth composed score plus
            // 3 normalised intermediates (q_gap_norm, q_var_norm,
            // grad_norm_norm). The underlying EMAs (q_gap_ema / q_var_ema /
            // grad_norm_ema in `health_ema`) reset at fold boundary, so the
            // composition outputs reset together via the standard Pearl A
            // sentinel-bootstrap path. Both halves of the contract reset
            // together: ISV slot zeroed AND wiener_state_buf SP5 block
            // bulk memset(0) at fold boundary covers the four new triples
            // at offsets [213+(290-174)*3 .. 213+(294-174)*3) = [561..573).
            RegistryEntry {
                name: "sp5_health_composition",
                category: ResetCategory::FoldReset,
                description: "ISV[HEALTH_SCORE_INDEX=290..GRAD_NORM_NORM_INDEX+1=294) — Layer D D2 LearningHealth composition outputs (composed score + q_gap_norm + q_var_norm + grad_norm_norm). SP5 Pearl A sentinel 0 at fold boundary so the new fold's first `launch_health_composition` fires the first-observation replacement (Task D2, 2026-05-02). Producer is `health_composition_kernel.cu` — single-block 1-thread arithmetic kernel reproducing `learning_health.rs::NormalizedComponents::from_raw` + `compose()` bit-for-bit. Consumer wires atomically in D4 (per `feedback_no_partial_refactor.md`). The underlying EMAs (`HealthEmaTrackers.q_gap_ema` / `q_var_ema` / `grad_norm_ema`, plus the 4 non-EMA inputs sourced from per-branch Q-gap dispersion / atom utilisation / spectral gap / Adam m-flat cosine) reset at fold boundary so the composition outputs reset together. Wiener-state companion: bulk memset of the entire `wiener_state_buf[0..(71 + SP5_PRODUCER_COUNT) × 3)` at fold boundary covers the D2 triples at offsets [213+(290-174)*3 .. 213+(294-174)*3) = [561..573). reset_for_fold's existing bulk memset of the whole buffer length covers these triples atomically — no per-slot wiener entry is needed. Buffer size derives from SP5_PRODUCER_COUNT to avoid drift on subsequent SPs.",
            },
            // SP5 Layer D Task D3: Training metrics EMA outputs (3 ISV slots).
            // ISV[294..297) — Layer D D3 host-formula EMAs for
            // `training_sharpe_ema` / `max_dd_ema` / `low_dd_ratio` migrated
            // from the host-side adversarial-regime + adaptive-DSR block at
            // `training_loop.rs:5039-5113`. The corresponding host scalars
            // (`training_sharpe_ema` + `_initialized`, `max_dd_ema`,
            // `low_dd_ratio`) reset at fold boundary on the host side
            // (constructor.rs:587-588/710-712 sets them to zero on each
            // construction; D4 will route the per-fold reset through the
            // existing fold-reset codepath alongside this ISV-side
            // sentinel). All three ISV slots take the standard Pearl A
            // sentinel-bootstrap path. Both halves of the contract reset
            // together: ISV slot zeroed AND `wiener_state_buf` SP5 block
            // bulk memset(0) at fold boundary covers the three new triples
            // at offsets [213+(294-174)*3 .. 213+(297-174)*3) = [573..582).
            RegistryEntry {
                name: "sp5_training_metrics_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[TRAINING_SHARPE_EMA_INDEX=294..LOW_DD_RATIO_INDEX+1=297) — Layer D D3 training-metrics EMA outputs (training_sharpe_ema / max_dd_ema / low_dd_ratio). SP5 Pearl A sentinel 0 at fold boundary so the new fold's first `launch_training_metrics_ema` fires the first-observation replacement (Task D3, 2026-05-02). Producer is `training_metrics_ema_kernel.cu` — single-block 3-thread arithmetic kernel (one thread per metric) reproducing the host-side adaptive-α Sharpe EMA + fixed-α=0.1 max_dd EMA + fixed-α=0.15 low_dd_ratio EMA from `training_loop.rs:5039-5113` bit-for-bit. Consumer wires atomically in D4 (per `feedback_no_partial_refactor.md`). The underlying host scalars (`training_sharpe_ema` + `_initialized`, `max_dd_ema`, `low_dd_ratio` on `DQNTrainer`) reset at fold boundary alongside the ISV slots — D4 ties the host-side fold-reset call into the same path. Wiener-state companion: bulk memset of the entire `wiener_state_buf[0..(71 + SP5_PRODUCER_COUNT) × 3)` at fold boundary covers the D3 triples at offsets [213+(294-174)*3 .. 213+(297-174)*3) = [573..582). reset_for_fold's existing bulk memset of the whole buffer length covers these triples atomically — no per-slot wiener entry is needed. Buffer size derives from SP5_PRODUCER_COUNT to avoid drift on subsequent SPs. Per `feedback_trust_code_not_docs.md` the third metric is `low_dd_ratio` (the binary low-drawdown indicator EMA at `training_loop.rs:5052`), not the speculative `gamma_blend` referenced in the SP5 plan §D Task D3 — that field does not exist in the codebase.",
            },
            // ── SP17 (2026-05-08): dueling-Q identifiability diagnostics ──────
            // Nine slots [474..483) driving the V/A diagnostic chain that
            // observes whether the post-SP17 mean-centered advantage is
            // doing real work and detects regression to the pre-SP17
            // V-dominated regime. Producer + consumer kernels land in the
            // 4-commit Phase 1-3 atomic migration (compute_expected_q +
            // c51_loss + c51_grad + mag_concat_qdir mean-centering) per
            // `feedback_no_partial_refactor`; this commit is additive
            // infrastructure only. All Pearl-A first-observation
            // bootstraps. Plan:
            // docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.
            RegistryEntry {
                name: "sp17_a_var_ema_dir",
                category: ResetCategory::FoldReset,
                description: "ISV[A_VAR_EMA_DIR_INDEX=474] — SP17 per-branch EMA of the over-actions variance of the centered advantage `A_centered[a, z] = A[a, z] − mean_a A[a, z]` for the direction branch (4 actions: Long/Short/Hold/Flat). Diagnostic only; signals dueling-Q identifiability health (Var → 0 = `all actions equivalent, V dominates` = pre-SP17 pathology re-emerging; Var > 0 with stable V_share ≈ 0.5 = healthy decomposition). FoldReset sentinel SENTINEL_A_VAR_EMA=0.0 — Pearl-A first-observation bootstrap per `pearl_first_observation_bootstrap.md`. Producer + consumer wire in Phase 1-3 of SP17 (atomic across compute_expected_q + c51_loss + c51_grad + mag_concat_qdir mean-centering) — not yet wired in this commit. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_a_var_ema_mag",
                category: ResetCategory::FoldReset,
                description: "ISV[A_VAR_EMA_MAG_INDEX=475] — SP17 per-branch EMA of the over-actions variance of `A_centered` for the magnitude branch (Quarter/Half/Full). Same contract/sentinel as slot 474. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_a_var_ema_ord",
                category: ResetCategory::FoldReset,
                description: "ISV[A_VAR_EMA_ORD_INDEX=476] — SP17 per-branch EMA of the over-actions variance of `A_centered` for the order branch. Same contract/sentinel as slot 474. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_a_var_ema_urg",
                category: ResetCategory::FoldReset,
                description: "ISV[A_VAR_EMA_URG_INDEX=477] — SP17 per-branch EMA of the over-actions variance of `A_centered` for the urgency branch. Same contract/sentinel as slot 474. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_v_share_dir",
                category: ResetCategory::FoldReset,
                description: "ISV[V_SHARE_DIR_INDEX=478] — SP17 per-branch magnitude share `|V_contribution| / (|V_contribution| + |A_centered|)` for the direction branch. Diagnostic only; signals dueling-Q identifiability health (V_share → 1.0 with Var(A_centered) → 0 = pre-SP17 V-dominated pathology). FoldReset sentinel SENTINEL_V_SHARE=0.5 — Pearl-A bootstrap interpreted as cold-start `healthy 50/50 split` (rather than 0.0) so the diagnostic chain doesn't flag the very first launch as pathological before any observation has landed. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_v_share_mag",
                category: ResetCategory::FoldReset,
                description: "ISV[V_SHARE_MAG_INDEX=479] — SP17 per-branch magnitude share for the magnitude branch. Same contract/sentinel as slot 478. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_v_share_ord",
                category: ResetCategory::FoldReset,
                description: "ISV[V_SHARE_ORD_INDEX=480] — SP17 per-branch magnitude share for the order branch. Same contract/sentinel as slot 478. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_v_share_urg",
                category: ResetCategory::FoldReset,
                description: "ISV[V_SHARE_URG_INDEX=481] — SP17 per-branch magnitude share for the urgency branch. Same contract/sentinel as slot 478. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            RegistryEntry {
                name: "sp17_advantage_clip_bound",
                category: ResetCategory::FoldReset,
                description: "ISV[ADVANTAGE_CLIP_BOUND_INDEX=482] — SP17 adaptive |A_centered| upper bound, producer-tracked from `p99(|A_centered|) × ADVANTAGE_CLIP_SAFETY_FACTOR=1.5` (mirrors SP14 P0-A REWARD_POS_CAP producer pattern). FoldReset sentinel SENTINEL_ADVANTAGE_CLIP_BOUND=1.0 — Pearl-A bootstrap interpreted as cold-start `no effective clipping` (1.0 ≫ typical |A_centered| early in training when A → 0; clip is a no-op until the first valid observation lands a real bound). α=ADVANTAGE_CLIP_EMA_ALPHA=0.01 slow per-fold cadence — the bound shouldn't track per-batch noise. Bilateral clamp to `[ADVANTAGE_CLIP_BOUND_MIN=0.1, ADVANTAGE_CLIP_BOUND_MAX=100.0]` per `pearl_symmetric_clamp_audit.md` — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`: floor 0.1 below which centered advantage is essentially noise (clipping would erase the action signal); ceiling 100.0 above which a single adversarial outlier dominates per-batch EMAs. NEVER hardcoded — adaptive bound. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
            },
            // ── SP18 v2 Pre-Phase Task PP.3 (2026-05-08): combined Hold-attractor fix ──
            // 22 ISV slots [483..505) split across two atomic legs per the v2
            // combined plan. D-leg [483..493) — 10 slots driving the structural
            // Hold opportunity-cost reward chain (replaces SP13 P0a + SP16 P2 +
            // SP16 T3 reactive per-bar Hold-cost chain per DD7=c). B-leg
            // [493..505) — 12 slots driving the TD(λ) Q(s') bootstrap chain
            // (replaces self-bootstrap q_next = rewards at gpu_experience_
            // collector.rs:4143 with real per-branch DDQN target-Q via target-
            // net forward pass on next_states). Producer + consumer kernels
            // land in Phases 2-7 atomic per `feedback_no_partial_refactor`;
            // this Pre-Phase commit is additive infrastructure only. All
            // sentinels are Pearl-A first-observation bootstrap except slot
            // 497 POPART_RESET_FLAG (sentinel 1.0 — one-shot per B-DD11,
            // gates per-fold PopArt slot 63 EMA reset at SP18 deployment
            // boundary). Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md.
            RegistryEntry {
                name: "sp18_hold_reward_pos_cap",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_REWARD_POS_CAP_INDEX=483] — SP18 D-leg adaptive upper bound on the structural Hold opportunity-cost reward (Hold during a losing bar). Producer-tracked from `p99(|step_ret|)` over Long/Short trade closes × HOLD_REWARD_CAP_SAFETY_FACTOR=1.5 (DD3=b) by `hold_reward_cap_update_kernel` (lands in Phase 3) with Wiener-optimal α from Welford accumulators in [487..493) per `pearl_wiener_optimal_adaptive_alpha`. FoldReset sentinel SENTINEL_HOLD_REWARD_POS_CAP=5.0 — Pearl-A first-observation bootstrap matching the SP14 P0-A REWARD_POS_CAP_ADAPTIVE pattern for bit-identical cold-start before the cap producer's first valid launch. Consumer: `compute_sp18_hold_opportunity_cost` device function in `trade_physics.cuh` (added Phase 2) consumes pos_cap as the upper bound on the opportunity-cost reward returned to the 3 Hold-cost subtraction sites in `experience_kernels.cu`. Bounds [HOLD_REWARD_POS_CAP_MIN_BOUND=0.5, HOLD_REWARD_POS_CAP_MAX_BOUND=50.0] are Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`. Producer + consumer wire in Phase 2-3 of SP18 (atomic 3-site migration) — not yet wired in this Pre-Phase commit. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md.",
            },
            RegistryEntry {
                name: "sp18_hold_reward_neg_cap",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_REWARD_NEG_CAP_INDEX=484] — SP18 D-leg adaptive lower bound on the structural Hold opportunity-cost reward (Hold during a winning bar — the missed-winner case). Producer writes NEG = -2 × POS (DD5=b mirrored 2:1 loss-aversion ratio matching SP14 P0-A REWARD_POS/NEG_CAP — preserves the Kahneman/Tversky prospect-theory asymmetry: missing a winner is the bigger pain, drives the policy toward engagement). FoldReset sentinel SENTINEL_HOLD_REWARD_NEG_CAP=-10.0 — Pearl-A first-observation bootstrap matching SP14 P0-A REWARD_NEG_CAP_ADAPTIVE for bit-identical cold-start. Same producer kernel as slot 483 (`hold_reward_cap_update_kernel`) writes both slots in one launch. Consumer: `compute_sp18_hold_opportunity_cost` device function applies the asymmetric clamp via `compute_asymmetric_capped_pnl(-2 × vol_normalized_log_return, neg_cap, pos_cap)`. Producer + consumer wire in Phase 2-3 of SP18 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md.",
            },
            RegistryEntry {
                name: "sp18_hold_reward_decomp_diag",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_REWARD_DECOMP_DIAG_INDEX=485] — SP18 D-leg HEALTH_DIAG observability slot for the per-action-bin reward decomposition diagnostic introduced in Phase 0 (per-bar EMAs of r_micro / r_opp_cost / r_popart / fire_rate per Hold/Long/Short/Flat action bin, surfaced by the new `reward_decomp_diag_kernel.cu`). FoldReset sentinel SENTINEL_HOLD_REWARD_DIAG=0.0 — Pearl-A direct-replace on first valid observation. Diagnostic only — does NOT modify any consumer path. Phase 0 KILL CRITERION evaluator reads this slot to abort D-leg if the per-step Hold-cost magnitude is already disproportionately large pre-fix (the controller is winning). Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § Phase 0.",
            },
            RegistryEntry {
                name: "sp18_hold_opp_cost_fire_rate_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_OPP_COST_FIRE_RATE_EMA_INDEX=486] — SP18 D-leg engagement canary: fraction of bars on which the new Hold opportunity-cost reward fires (non-zero) — should be ≈ Hold% itself once the structural reward is wired. FoldReset sentinel SENTINEL_HOLD_OPP_FIRE_RATE=0.0 — Pearl-A direct-replace on first valid observation. Sanity-checks the structural-reward producer is actually emitting non-zero on Hold bars (pre-Phase-3 sentinel-bootstrap pre-fires the per-bar zero, post-Phase-3 should track the realised Hold rate). Producer kernel embeds the fire-rate EMA update into the same launch that consumes the new opportunity-cost reward. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § Phase 3.",
            },
            // ── HRC_* Welford accumulators (D-leg, mirrors SP16 T3 HCS_* layout)
            RegistryEntry {
                name: "sp18_hrc_target_mean",
                category: ResetCategory::FoldReset,
                description: "ISV[HRC_TARGET_MEAN_INDEX=487] — SP18 D-leg Welford running mean of target_cap for the `hold_reward_cap_update_kernel` producer. Sentinel 0.0; first valid observation initialises via Welford increment. Combined with the cold-start fallback (sample_count<3 → α=1.0 REPLACE), the first 3 epochs of each fold force REPLACE; from epoch 3 onward Wiener-optimal α emerges from Welford state per `pearl_wiener_optimal_adaptive_alpha`.",
            },
            RegistryEntry {
                name: "sp18_hrc_target_m2",
                category: ResetCategory::FoldReset,
                description: "ISV[HRC_TARGET_M2_INDEX=488] — SP18 D-leg Welford ΣΔ² (sample-variance accumulator) for target_cap in the `hold_reward_cap_update_kernel` producer. Sentinel 0.0; tracks variance of `target_cap` series across each fold. Used to compute `sample_var = M2 / (n - 1)` once `n ≥ 3`.",
            },
            RegistryEntry {
                name: "sp18_hrc_diff_mean",
                category: ResetCategory::FoldReset,
                description: "ISV[HRC_DIFF_MEAN_INDEX=489] — SP18 D-leg Welford running mean of consecutive `target_cap` one-step diffs in the `hold_reward_cap_update_kernel` producer. Sentinel 0.0; first diff observation lands when sample_count reaches 2.",
            },
            RegistryEntry {
                name: "sp18_hrc_diff_m2",
                category: ResetCategory::FoldReset,
                description: "ISV[HRC_DIFF_M2_INDEX=490] — SP18 D-leg Welford ΣΔ² for the consecutive-diff series in the `hold_reward_cap_update_kernel` producer. Sentinel 0.0; provides `diff_var` half of the Wiener formula α = diff_var / (diff_var + sample_var + ε).",
            },
            RegistryEntry {
                name: "sp18_hrc_prev_target",
                category: ResetCategory::FoldReset,
                description: "ISV[HRC_PREV_TARGET_INDEX=491] — SP18 D-leg previous-epoch `target_cap` for the `hold_reward_cap_update_kernel` producer. Sentinel 0.0; written every launch from the freshly-computed `target_cap` so the next launch's diff calculation has a basis.",
            },
            RegistryEntry {
                name: "sp18_hrc_sample_count",
                category: ResetCategory::FoldReset,
                description: "ISV[HRC_SAMPLE_COUNT_INDEX=492] — SP18 D-leg Welford observation counter for the `hold_reward_cap_update_kernel` producer. Sentinel 0.0; incremented every launch (excluding cold-start sentinel-guard early-return). The cold-start fallback (sample_count < WELFORD_MIN_SAMPLE_COUNT=3 → α = 1.0 REPLACE) keeps the producer responsive in epochs 1-2 of each fold while Welford state stabilises.",
            },
            // ── B-leg observability + reset gate slots [493..505) ─────────────
            RegistryEntry {
                name: "sp18_td_error_mag_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[TD_ERROR_MAG_EMA_INDEX=493] — SP18 B-leg HEALTH_DIAG observable: `avg(|TD-error|)` computed post-fix from the per-batch L1 norm of `td_errors` (already computed for PER priority recomputation at training time). FoldReset sentinel SENTINEL_TD_ERROR_MAG_EMA=0.0 — Pearl-A direct-replace on first valid observation. The B-DD9 ratio gate compares post-fix / pre-fix at HD0–HD1 (target [0.5, 5.0]) — ratio outside that range = bootstrap change blew up loss magnitude. Producer + consumer wire in Phase 0 (diagnostic emit) + Phase 8 (combined HEALTH_DIAG emit) of SP18 — not yet wired in this Pre-Phase commit. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § B-DD9 + B-DD12.",
            },
            RegistryEntry {
                name: "sp18_q_next_target_p99",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_NEXT_TARGET_P99_INDEX=494] — SP18 B-leg HEALTH_DIAG observable: p99 of the new target-Q bootstrap value (the per-branch DDQN sum-of-argmaxed target-Q across dir/mag/ord/urg branches that replaces `q_next = rewards`). FoldReset sentinel 0.0 — Pearl-A direct-replace. Bound check on the new path (catches blow-up if target net diverges). Producer + consumer wire in Phase 4-5 of SP18 — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § B-DD12.",
            },
            RegistryEntry {
                name: "sp18_q_next_minus_reward_p99",
                category: ResetCategory::FoldReset,
                description: "ISV[Q_NEXT_MINUS_REWARD_P99_INDEX=495] — SP18 B-leg HEALTH_DIAG observable: p99 of `|q_next_target − rewards|`. FoldReset sentinel 0.0 — Pearl-A direct-replace. Sanity check that the new bootstrap is doing real work — should be O(1) post-fix (NOT O(0) which would mean q_next_target ≈ rewards, i.e. the fix is doing nothing; NOT O(100) which would mean it's blowing up). Pre-fix this slot would be ~0 because q_next *was* rewards. Producer + consumer wire in Phase 4-5 of SP18 — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § B-DD12.",
            },
            RegistryEntry {
                name: "sp18_v_share_trend_diag",
                category: ResetCategory::FoldReset,
                description: "ISV[V_SHARE_TREND_DIAG_INDEX=496] — SP18 B-leg HEALTH_DIAG observable: slope of the SP17 V_SHARE EMA (slots [478..482)) across the last 4 epochs, computed as `(EMA[now] - EMA[now-4]) / 4`. FoldReset sentinel 0.0 — Pearl-A direct-replace. The B-leg synergy hypothesis (pearl_TBD: bootstrap-bias drives v_share elevation) predicts v_share monotone HD0→HD4 pre-fix; post-fix the slope should *flatten* or *reverse*. Slope < 0 OR slope ≤ 0.05 with v_share[HD3] > 0.7 = synergy hypothesis confirmed; otherwise B-leg KILL CRITERION fires. Producer + consumer wire in Phase 0 (diagnostic emit) of SP18 — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § Phase 0.",
            },
            RegistryEntry {
                name: "sp18_popart_reset_flag",
                category: ResetCategory::FoldReset,
                description: "ISV[POPART_RESET_FLAG_INDEX=497] — SP18 B-leg per-fold PopArt EMA reset gate per B-DD11. FoldReset sentinel SENTINEL_POPART_RESET_FLAG=1.0 (NOT 0.0 — this is the only non-zero diagnostic sentinel in the 22-slot SP18 block). Each fold start, the FoldReset machinery writes 1.0 here; on the first epoch of that fold the PopArt-reset consumer kernel (Phase 5) reads 1.0, clamps PopArt slot 63 EMA back to identity normalization (μ=0, σ=1), and writes 0.0 back to slot 497 — making it one-shot per fold. Switching `q_next` source from rewards-distributed to Q-distributed (Phase 5 atomic refactor) shifts the input distribution to PopArt; PopArt's α-EMA will adapt but may take 1+ epochs. The reset is cheap insurance. Producer + consumer wire in Phase 5 of SP18 — not yet wired in this Pre-Phase commit. Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md § B-DD11.",
            },
            // ── TDB_* Welford accumulators (B-leg, mirrors HRC_* layout) ──────
            RegistryEntry {
                name: "sp18_tdb_target_mean",
                category: ResetCategory::FoldReset,
                description: "ISV[TDB_TARGET_MEAN_INDEX=498] — SP18 B-leg Welford running mean of q_next_target for the post-fix Wiener-α blend on the TD-error magnitude EMA. Sentinel 0.0; same Welford algorithm as the D-leg HRC counterpart at slot 487 but tracks q_next_target instead of target_cap. Combined with the cold-start fallback (sample_count<3 → α=1.0), the first 3 epochs of each fold force REPLACE; from epoch 3 onward Wiener-optimal α emerges. Producer wire in Phase 4 of SP18 — not yet wired.",
            },
            RegistryEntry {
                name: "sp18_tdb_target_m2",
                category: ResetCategory::FoldReset,
                description: "ISV[TDB_TARGET_M2_INDEX=499] — SP18 B-leg Welford ΣΔ² for q_next_target. Sentinel 0.0; mirrors HRC_TARGET_M2_INDEX=488 modulo the producer it serves. Producer wire in Phase 4 — not yet wired.",
            },
            RegistryEntry {
                name: "sp18_tdb_diff_mean",
                category: ResetCategory::FoldReset,
                description: "ISV[TDB_DIFF_MEAN_INDEX=500] — SP18 B-leg Welford running mean of consecutive q_next_target diffs. Sentinel 0.0; mirrors HRC_DIFF_MEAN_INDEX=489. Producer wire in Phase 4 — not yet wired.",
            },
            RegistryEntry {
                name: "sp18_tdb_diff_m2",
                category: ResetCategory::FoldReset,
                description: "ISV[TDB_DIFF_M2_INDEX=501] — SP18 B-leg Welford ΣΔ² for the consecutive-diff series. Sentinel 0.0; provides `diff_var` half of the Wiener formula. Mirrors HRC_DIFF_M2_INDEX=490. Producer wire in Phase 4 — not yet wired.",
            },
            RegistryEntry {
                name: "sp18_tdb_prev_target",
                category: ResetCategory::FoldReset,
                description: "ISV[TDB_PREV_TARGET_INDEX=502] — SP18 B-leg previous-epoch q_next_target. Sentinel 0.0; mirrors HRC_PREV_TARGET_INDEX=491. Producer wire in Phase 4 — not yet wired.",
            },
            RegistryEntry {
                name: "sp18_tdb_sample_count",
                category: ResetCategory::FoldReset,
                description: "ISV[TDB_SAMPLE_COUNT_INDEX=503] — SP18 B-leg Welford observation counter. Sentinel 0.0; cold-start fallback (sample_count < 3 → α = 1.0) ensures the first 3 epochs of each fold force REPLACE so the Welford-derived α takes over from epoch 3 onward. Mirrors HRC_SAMPLE_COUNT_INDEX=492. Producer wire in Phase 4 — not yet wired.",
            },
            RegistryEntry {
                name: "sp18_b_leg_reserved",
                category: ResetCategory::FoldReset,
                description: "ISV[SP18_B_LEG_RESERVED_INDEX=504] — SP18 B-leg RESERVED slot for follow-up if needed (e.g. distributional flavour of B-DD8 if 5-epoch smoke shows atom-distribution drift). Sentinel 0.0. No producer or consumer in the Pre-Phase scope — preserves the 12-slot B-leg block aligned and the layout fingerprint stable.",
            },
            // ── SP18 v2 ISV-adaptive shrink-and-perturb (2026-05-09) ─────
            // 2 ISV slots [505..507) drive `reset_for_fold`'s
            // `shrink_and_perturb` call replacing prior hardcoded
            // `α=0.8 / σ=0.01` constants per
            // `feedback_isv_for_adaptive_bounds` and
            // `feedback_adaptive_not_tuned`. Producer kernel is the
            // existing `weight_drift_diag_update` (`weight_drift_diag_kernel.cu`,
            // commit `aab13a83f`) extended atomically in this commit to
            // ALSO write α and σ from the same two block-tree-reductions.
            // Pearl-A first-observation bootstrap sentinels match prior
            // hardcoded values for bit-identical cold-start before the
            // first valid drift-kernel launch.
            RegistryEntry {
                name: "sp18_shrink_alpha_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[SHRINK_ALPHA_ADAPTIVE_INDEX=505] — SP18 v2 adaptive shrink factor for `reset_for_fold`'s `shrink_and_perturb` call. Drift-driven: when end-of-fold relative drift `||current − best||₂ / ||best||₂` is small (model converged near best), α high (preserve); large drift → α low (shrink harder to escape divergent region). Formula: α_target = 1 − clamp(relative_drift, 1 − ALPHA_MAX, 1 − ALPHA_MIN). FoldReset sentinel SENTINEL_SHRINK_ALPHA=0.8 — Pearl-A first-observation bootstrap matching the prior hardcoded `α=0.8` for bit-identical cold-start before the first valid drift-kernel launch (first fold has no `best_params_snapshot` → host launcher skips kernel → slot stays at sentinel). Bounds [SHRINK_ALPHA_MIN=0.5, SHRINK_ALPHA_MAX=0.95] are Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds` — never less than 50% preservation (catastrophic-forgetting guard) / never more than 95% (some perturbation always — preserves the noise-injection effect that breaks overfitting to the prior fold). Bilateral clamp per `pearl_symmetric_clamp_audit`. Producer + consumer wired in the same commit per `feedback_no_partial_refactor`.",
            },
            RegistryEntry {
                name: "sp18_shrink_sigma_adaptive",
                category: ResetCategory::FoldReset,
                description: "ISV[SHRINK_SIGMA_ADAPTIVE_INDEX=506] — SP18 v2 adaptive noise scale for `reset_for_fold`'s `shrink_and_perturb` call. Scale-aware: σ tracks `||best||_RMS = ||best||₂ / sqrt(n)` so noise stays scale-relative as weight magnitudes evolve across folds (LayerNorm γ drift, weight-decay relaxation). Formula: σ_target = clamp(SENTINEL_SHRINK_SIGMA × (best_rms / SHRINK_SIGMA_RMS_REFERENCE), SIGMA_MIN, SIGMA_MAX). At RMS = REFERENCE = 0.5 (Category-1 dimensional anchor — typical mean RMS of healthy stably-trained DQN weights), σ = SENTINEL = 0.01 → bit-identical to prior hardcoded value for typical healthy weights. FoldReset sentinel SENTINEL_SHRINK_SIGMA=0.01 — Pearl-A first-observation bootstrap matching the prior hardcoded `σ=0.01` for bit-identical cold-start. Bounds [SHRINK_SIGMA_MIN=1e-4, SHRINK_SIGMA_MAX=0.1] are Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds` — floor prevents zero-noise (gradient bias if perturbation vanishes) / ceiling prevents destructive noise (10× sentinel; ratio caps σ growth on weight-magnitude excursions). Bilateral clamp per `pearl_symmetric_clamp_audit`. Same producer kernel as slot 505 (`weight_drift_diag_update` writes both in one launch).",
            },
            // ── SP19 (2026-05-09) — producer-side multi-horizon reward blend weights ──
            // 3 ISV slots [507..510) RESERVED for future controller-driven
            // multi-horizon reward blending. Path (B) of the SP19 spec
            // applies the blend at fxcache write time (`precompute_features.rs`
            // / `data_loading.rs`) using a hardcoded equal-thirds default;
            // these slots are slot reservations, NOT yet read by any kernel
            // consumer. Sentinels match the producer-time hardcoded
            // `SP19_HORIZON_BLEND_WEIGHTS` (1/3 each) for bit-identical
            // cold-start with the on-disk fxcache. Per `feedback_no_partial_refactor`
            // the slot reservations land alongside the producer change in
            // the same atomic branch (split into Commit A + Commit B for
            // bisect-friendliness, but never on `main` separately).
            RegistryEntry {
                name: "sp19_reward_horizon_weight_1bar",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_HORIZON_WEIGHT_1BAR_INDEX=507] — SP19 Path (B) reservation slot for the 1-bar horizon weight in the producer-side multi-horizon reward blend. NOT consumed at producer time (producer hardcodes 1/3); reserved for future Path (A) refactor that bumps TARGET_DIM to carry per-horizon log-returns through the kernel pipeline. FoldReset sentinel SENTINEL_REWARD_HORIZON_WEIGHT_DEFAULT=1/3 — Pearl-A first-observation bootstrap matching the producer's hardcoded `SP19_HORIZON_BLEND_WEIGHTS = [1/3, 1/3, 1/3]` so on-disk fxcache values stay bit-identical to slot reads when Path (A) eventually consumes them. Per `feedback_isv_for_adaptive_bounds` the slot reservations are documented forward-compatibility, NOT a half-fix.",
            },
            RegistryEntry {
                name: "sp19_reward_horizon_weight_5bar",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_HORIZON_WEIGHT_5BAR_INDEX=508] — SP19 Path (B) reservation slot for the 5-bar horizon weight in the producer-side multi-horizon reward blend. NOT consumed at producer time (producer hardcodes 1/3 with vol-scale `1/sqrt(5)` correction); reserved for future Path (A) refactor. FoldReset sentinel SENTINEL_REWARD_HORIZON_WEIGHT_DEFAULT=1/3 — matches producer hardcoded `SP19_HORIZON_BLEND_WEIGHTS[1] = 1/3`. The vol-scale correction stays in the producer regardless of weight changes — multiplying log-returns by `1/sqrt(N)` makes them comparable across horizons before blending.",
            },
            RegistryEntry {
                name: "sp19_reward_horizon_weight_30bar",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_HORIZON_WEIGHT_30BAR_INDEX=509] — SP19 Path (B) reservation slot for the 30-bar horizon weight in the producer-side multi-horizon reward blend. NOT consumed at producer time (producer hardcodes 1/3 with vol-scale `1/sqrt(30)` correction); reserved for future Path (A) refactor. FoldReset sentinel SENTINEL_REWARD_HORIZON_WEIGHT_DEFAULT=1/3 — matches producer hardcoded `SP19_HORIZON_BLEND_WEIGHTS[2] = 1/3`. 30-bar horizon trims `LOOKAHEAD_HORIZON_MAX = 30` bars from the dataset tail at producer time; tail bars without 30 future bars are excluded.",
            },
            // ─────── SP20 slots [510..520) — WR-first optimization ──────────────
            // 10 ISV controller outputs + diagnostics, all Wiener-α EMAs or
            // controller state; registered with sentinel = 0.0 per
            // pearl_first_observation_bootstrap. First observation replaces
            // sentinel directly, no blending.
            RegistryEntry {
                name: "loss_cap",
                category: ResetCategory::FoldReset,
                description: "ISV[LOSS_CAP_INDEX=510] — SP20 adaptive loss cap for reward clamp; Wiener-α EMA tracking label noise floor; sentinal 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "alpha_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[ALPHA_EMA_INDEX=511] — SP20 Wiener-α EMA for loss_cap producer; tracks EMA adaptation pace; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "wr_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[WR_EMA_INDEX=512] — SP20 win-rate EMA driving loss_cap adaptive ramp; Wiener smoothed trade outcome frequency; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "hold_cost_scale",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_COST_SCALE_INDEX=513] — SP20 hold penalty cost multiplier; scales hold duration cost; Wiener-α EMA; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "target_hold_pct",
                category: ResetCategory::FoldReset,
                description: "ISV[TARGET_HOLD_PCT_INDEX=514] — SP20 hold-engagement target; controller setpoint for hold rate; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "hold_pct_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_PCT_EMA_INDEX=515] — SP20 hold-engagement EMA; actual hold % smoothed; Wiener-α tracked; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "hold_reward_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[HOLD_REWARD_EMA_INDEX=516] — SP20 hold-action reward EMA; integral of per-trade hold contribution; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "n_step",
                category: ResetCategory::FoldReset,
                description: "ISV[N_STEP_INDEX=517] — SP20 multi-step TD horizon adapter; tracks multi-bar lookahead depth; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "aux_conf_threshold",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_CONF_THRESHOLD_INDEX=518] — SP20 auxiliary task confidence threshold gating; EMA of prediction confidence floor; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            RegistryEntry {
                name: "aux_gate_temp",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_GATE_TEMP_INDEX=519] — SP20 auxiliary task gating temperature; controls softmax sharpness on aux-path selection; sentinel 0.0 bootstrap per pearl_first_observation_bootstrap",
            },
            // ── SP20 Phase 1.4 (2026-05-09, Path C): non-ISV scratch buffer
            // resets owned by the experience collector. Mapped-pinned
            // `host_slice_mut().fill(0.0/0)` resets — the buffers are
            // device-visible via `cuMemHostAlloc(DEVICEMAP)` so the host
            // write is allowed under `feedback_no_htod_htoh_only_mapped_pinned`'s
            // allowed-write rule (NOT a host-side compute).
            RegistryEntry {
                name: "sp20_ema_inputs_buf",
                category: ResetCategory::FoldReset,
                description: "SP20 Phase 1.4 mapped-pinned [9] f32 scratch buffer holding the SP20EmaInputs struct between aggregate→EMAs kernels. FoldReset zeros all 9 slots; the aggregation kernel rewrites every byte each step so the reset is purely defensive (clears any inherited bit pattern). Bridges the per-env collector arrays to the post-Path-C EMA kernel struct contract per `feedback_no_partial_refactor`.",
            },
            RegistryEntry {
                name: "sp20_emas_internal_buf",
                category: ResetCategory::FoldReset,
                description: "SP20 Phase 1.4 mapped-pinned [4] f32 internal scratch for `sp20_emas_compute_kernel`: trade_duration_ema (slot 0), aux_conf_p50_ema (slot 1), aux_conf_std_ema (slot 2), aux_dir_acc_ema (slot 3). FoldReset zeros all 4 — Pearl-A first-observation bootstrap re-engages on each fold's first per-trade / per-step firing observation. Read by `sp20_controllers_compute_kernel` to derive N_STEP / TARGET_HOLD_PCT / AUX_GATE_TEMP / AUX_CONF_THRESHOLD.",
            },
            RegistryEntry {
                name: "sp20_emas_obs_count_buf",
                category: ResetCategory::FoldReset,
                description: "SP20 Phase 1.4 mapped-pinned [8] i32 per-EMA observation counter for `sp20_emas_compute_kernel`. counter==0 ⇒ next firing observation REPLACES sentinel directly (Pearl-A bootstrap); counter>0 ⇒ Wiener-blend with α=0.4 floor. FoldReset zeros all 8 counters so each fold's first per-EMA firing observation re-bootstraps from sentinel — necessary because some EMAs legitimately observe 0.0 and the count-based bootstrap is the correct sentinel discriminator per `pearl_first_observation_bootstrap`.",
            },
            // ── SP20 Phase 2 Task 2.0 (2026-05-09): per-env trade-open
            // label sign scratch — written at `entering_trade`, read at
            // `is_close` by the SP20 4-quadrant reward kernel.
            RegistryEntry {
                name: "label_at_open_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.label_at_open_per_env [alloc_episodes] i32 device-resident scratch — SP20 Phase 2 Task 2.0 (2026-05-09) per-env aux next-bar label sign captured at trade open. Layout: tile[env] in {-1, 0, +1} where +1 = aux predicted up at trade open, -1 = aux predicted not-up, 0 = sentinel (no position currently open or trade-open landed in aux skip-window). Producer: `experience_env_step` `entering_trade` branch — reads `exp_aux_nb_label_buf[env]` (kernel emits `0`/`1`/`-1` per `aux_sign_label_per_step_kernel.cu:77`) and maps `0`→`-1`, `1`→`+1`, `-1`→`0` to match the SP20 spec sign convention (spec §4.1: `label_at_open = sign(SP19_blended_label[trade_open_bar])`). Consumer: `experience_env_step` `is_close` branch — passes `label_at_open_per_env[env]` to `sp20_compute_event_reward(close_pnl, label_at_open_sign, isv[LOSS_CAP_INDEX])`. FoldReset sentinel 0 across all `alloc_episodes` slots — leftover label from the previous fold's open trade would corrupt the new fold's first trade-close `dir_match` check (the new fold's aux head has independent calibration and would not have produced that label). Reset path: `cudarc::driver::CudaStream::memset_zeros` on the `CudaSlice<i32>` (device-resident, no host buffer to fill). Per `pearl_first_observation_bootstrap` the sentinel-0 input also flows through `sp20_compute_event_reward` to the wrong-reason quadrant on the corner case where a trade closes WITHOUT a prior `entering_trade` having fired this fold (trade carry-over from before the reset is impossible because portfolio_states is also FoldReset).",
            },
            // ── SP20 Phase 2 Task 2.2 (2026-05-09): per-env trade-close
            // alpha scratch — written at `is_close`, read by
            // `sp20_aggregate_inputs_kernel` to populate the
            // `EmaInputs.alpha` field (replacing the Phase 1.4 0.0f
            // forward-reference placeholder).
            RegistryEntry {
                name: "alpha_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.alpha_per_env [alloc_episodes] f32 device-resident scratch — SP20 Phase 2 Task 2.2 (2026-05-09) per-env trade-close alpha (= R_event - hold_baseline) per spec §4.1. Phase 2 emits `hold_baseline = 0.0f` as a Phase 3.2 forward-reference placeholder; Phase 3.2's Hold opportunity-cost dual emission lands the real `hold_baseline_buffer.sum_over_trade_range()` consumer. Producer: `experience_env_step` `is_close` (segment_complete) branch — writes `alpha = sp20_compute_event_reward(segment_return, label_at_open_per_env[env], ISV[LOSS_CAP_INDEX])`. Consumer: `sp20_aggregate_inputs_kernel` (Path C aggregation) — sums `alpha_per_env[env]` over closed envs and divides by closed-count to populate `EmaInputs.alpha`. FoldReset sentinel 0.0 across all `alloc_episodes` slots — leftover alpha from the previous fold's last trade-close would corrupt the new fold's first ALPHA_EMA observation. The sentinel-0 reads as `alpha == 0` for non-close steps; the aggregation kernel reads only when `trade_close_per_env[env] != 0` so the FoldReset sentinel never reaches the EMA. Reset path: `cudarc::driver::CudaStream::memset_zeros` on the `CudaSlice<f32>` (device-resident, no host buffer to fill). Replaces the Phase 1.4 hardcoded `out_inputs->alpha = 0.0f` placeholder atomically per `feedback_no_partial_refactor` (Task 2.2 lands buffer + kernel-arg + aggregation-kernel-update + 2 placeholder pin tests in one commit).",
            },
            // ── SP20 Phase 2 Task 2.2-fix (2026-05-10): per-env segment-
            // level win flag scratch. Companion to alpha_per_env, same
            // segment_complete producer site, same FoldReset semantics.
            RegistryEntry {
                name: "is_win_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.is_win_per_env [alloc_episodes] i32 device-resident scratch — SP20 Phase 2 Task 2.2-fix (2026-05-10) per-env segment-level win flag (1 iff segment_return > 0.0f at trade close, else 0). Producer: `experience_env_step` `is_close && segment_complete && segment_hold_time > 0.0f` branch — writes alongside `alpha_per_env[i] = alpha`. Consumer: `sp20_aggregate_inputs_kernel` reads `is_win_per_env[env]` to compute `wins_count` (replacing the broken per-bar `step_ret > 0` predicate; per-bar step_ret at close bars is dominated by tx_cost deduction → systematically negative even on winning trades, pinning WR_EMA at 0). FoldReset sentinel 0 across all `alloc_episodes` slots — leftover win flag from the previous fold's last trade-close would corrupt the new fold's first WR_EMA observation. The sentinel-0 reads as is_win=0 (not-won) for non-close steps; the aggregation kernel reads only when `trade_close_per_env[env] != 0` so the FoldReset sentinel never reaches the EMA. Reset path: `cudarc::driver::CudaStream::memset_zeros` on the `CudaSlice<i32>` (device-resident, no host buffer to fill).",
            },
            // ── SP20 Phase 3 Task 3.2 (2026-05-10): per-env Hold
            // opportunity-cost circular buffer. Component 2 producer/
            // consumer per spec §4.2. Written at every per-bar
            // branch (positioned-non-event + flat-non-event); summed
            // at trade-close to compute hold_baseline; replaces the
            // Phase 2 Task 2.2 forward-reference placeholder
            // `hold_baseline = 0.0f` atomically.
            RegistryEntry {
                name: "hold_baseline_buffer",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.hold_baseline_buffer [alloc_episodes × HOLD_BASELINE_BUFFER_SIZE = 30] f32 device-resident scratch — SP20 Phase 3 Task 3.2 (2026-05-10) per-env circular Hold opportunity-cost buffer per spec §4.2 (Component 2). Layout: row-major, `[env, current_t % 30]` slot per per-bar write. Producer: `experience_env_step` per-bar branches (positioned-non-event ~line 3650 + flat-non-event ~line 3737) — both write `hold_baseline_buffer[env, current_t % 30] = -aux_conf × cost_scale` UNCONDITIONALLY (Path 2 counterfactual emission, regardless of action; spec §4.2 line 225 `hold_baseline_buffer[i] = R_per_bar_i // uncentered, for Component 1`). Consumer: `experience_env_step` `is_close && segment_hold_time > 0.0f` branch — `hold_baseline = sp20_sum_hold_baseline_over_trade(buf, env, 30, current_t, segment_hold_time)` walking backwards `min(30, segment_hold_time)` slots from `(current_t - 1) % 30`. Replaces the Phase 2 Task 2.2 placeholder `hold_baseline = 0.0f` atomically per `feedback_no_partial_refactor`. FoldReset sentinel 0.0 across all `alloc_episodes × 30` slots — leftover per-bar costs from the previous fold's open trade would corrupt the new fold's first trade-close summation (the new fold's portfolio_states is also FoldReset so any trade open at fold boundary is impossible, but if a buffer slot retained a stale value it could leak into the first trade-close after fold reset via the modulo-arithmetic indexing). Reset path: `cudarc::driver::CudaStream::memset_zeros` on the `CudaSlice<f32>` (device-resident, no host buffer to fill). Per `pearl_first_observation_bootstrap`: cold-start with `ISV[HOLD_COST_SCALE_INDEX=513]` at sentinel 0 means `per_bar_opp_cost = 0` (Path 2 writes zeros to the buffer); the trade-close consumer sums zeros and lands `hold_baseline = 0.0f` (matches Phase 2 Task 2.2 placeholder behaviour bit-for-bit on the very first trade close after fold reset). The controller's first observation lifts cost_scale, then per-bar writes become non-zero, then the next trade-close summation engages — gracefully bootstrapped, no warmup gate needed.",
            },
            // SP22 H6 Phase 3 (2026-05-13) — aux→policy bypass routing.
            // Two new ISV slots backing β: the 7th reward component EMA and
            // the SP11-controller-emitted adaptive scale_β. Both FoldReset
            // sentinel 0 per `pearl_first_observation_bootstrap`.
            RegistryEntry {
                name: "sp22_reward_aux_align_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[REWARD_AUX_ALIGN_EMA_INDEX=536] — SP22 H6 Phase 3 (2026-05-13) EMA of the 7th reward component `r_aux_align` (β producer at trade-close). Producer: extended `reward_component_ema_kernel.cu` (0..7 iteration after the 7-component contract migration). Consumers: `reward_subsystem_controller_kernel.cu` (anchor signal for the new `w_aux_align` adaptive weight at ISV[SP22_AUX_ALIGN_SCALE_INDEX=537]); HEALTH_DIAG `reward_split` printer (the `aux_align=…` column); `health_diag_kernel.cu` snap layout (`snap.reward_split_aux_align`). FoldReset sentinel 0 — Pearl A bootstrap: first non-zero observation from the EMA producer replaces the sentinel directly. The β producer fires at `segment_complete` only when (a) policy direction aligns with aux conviction AND (b) trade was profitable, so cold-start with no aligned-profitable trades yet means the EMA stays at 0 until the first such trade closes; this is the correct cold-start behavior — no warmup gate needed.",
            },
            RegistryEntry {
                name: "sp22_aux_align_scale",
                category: ResetCategory::FoldReset,
                description: "ISV[SP22_AUX_ALIGN_SCALE_INDEX=537] — SP22 H6 Phase 3 (2026-05-13) SP11-controller-emitted adaptive scale_β for the β producer at trade-close. Producer (eventual): extended `reward_subsystem_controller_kernel.cu` (7-weight output, anchor on `REWARD_AUX_ALIGN_EMA_INDEX=536`, target ~10% of total reward magnitude, bounds [0.05, 2.0]) — Phase B6, NOT yet landed. Consumers: `experience_env_step::segment_complete` (training-side β: `r_aux_align = scale_β × alignment × profit_pos`) and `backtest_env_kernel::segment_complete` (eval-side β with the same formula); HEALTH_DIAG `sp11_reward` printer (the `w_aux=…` column). FoldReset sentinel 0.5 — structural prior matching W's [-0.5, 0, +0.5, 0] init approach; activates β with fixed magnitude from epoch 0. The 0.5 prior was chosen over 0 (the original spec) because slot 537 has no producer yet (Phase B6 deferred); 0 would make β a runtime no-op. Once B6 lands and the controller emits adaptively per the bounds [0.05, 2.0], the prior is overwritten on first emit per `pearl_first_observation_bootstrap`; subsequent EMA-driven adaptation tracks the anchor signal.",
            },
            // SP22 H6 vNext Phase F-3 (2026-05-14) — K=3 trade-outcome
            // head sparse-CE EMA for smoke validation observability.
            RegistryEntry {
                name: "aux_trade_outcome_ce_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[AUX_TRADE_OUTCOME_CE_EMA_INDEX=538] — SP22 H6 vNext Phase F-3 (2026-05-14) batch-mean sparse cross-entropy EMA of the K=3 trade-outcome aux head. Producer: `aux_outcome_ce_ema_update` kernel (single-thread, single-block, direct-to-ISV with Pearl A first-observation bootstrap, α=0.05). Reads `aux_to_loss_scalar_buf[0]` (written by `aux_trade_outcome_loss_reduce` inside the captured forward graph). Cold-start sentinel 0.0; Pearl A bootstrap replaces with the first non-zero observation. FoldReset sentinel 0.0 — each fold's first non-zero loss observation re-bootstraps the EMA from scratch (the head's training state is preserved across folds via Adam moments, but the per-fold loss distribution can shift slightly with the new fold's data). Consumers (initial): smoke validation observability — operator reads the slot via HEALTH_DIAG or ISV inspector to verify the head is learning (CE drops from ~1.098=ln(3) toward 0.5-0.7 over epochs if signal-rich; pinned at ln(3) if signal-poor).",
            },
            // SP22 H6 vNext Phase A3 (2026-05-13) — save-for-backward
            // buffers for the trade-outcome aux head's label producer.
            // Both written at every segment_complete bar alongside
            // alpha_per_env / is_win_per_env; consumed by the
            // trade_outcome_label_kernel at the next training step.
            RegistryEntry {
                name: "pnl_vs_target_at_close_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.pnl_vs_target_at_close_per_env [alloc_episodes] f32 device-resident scratch — SP22 H6 vNext Phase A3 (2026-05-13) per-env trade-close P&L ratio vs `plan_profit × equity` save-for-backward buffer. Producer: `experience_env_step` `is_close && segment_complete` branch — writes `plan_isv[PLAN_ISV_PNL_VS_TARGET]` (the local plan_isv value already computed at line ~874 from `f_unrealized_pnl / (plan_profit × f_equity + 1e-6f)` symmetrically clamped to [-2, +2] per `pearl_symmetric_clamp_audit`). Consumer (eventual, Phase A4/A5): `trade_outcome_label_kernel.cu`'s `pnl_vs_target_at_close` arg — `≥ 1.0` predicate classifies the closed trade as `Profit` (label 0) per the K=3 outcome taxonomy. FoldReset sentinel 0.0 across all `alloc_episodes` slots — leftover ratios from the previous fold's last trade-close would corrupt the new fold's first label production (0.0 sentinel reads as 'no threshold hit' → classifies as Timeout if a stale read leaked, but the label kernel reads only when `trade_close_per_sample != 0` so the sentinel never reaches the loss). Reset path: `cudarc::driver::CudaStream::memset_zeros` on the `CudaSlice<f32>` (device-resident, no host buffer to fill). Phase A3 (this commit) lands the buffer + producer write + FoldReset wiring atomically per `feedback_no_partial_refactor`; the consumer (label kernel launcher) lands in Phase A4/A5.",
            },
            RegistryEntry {
                name: "pnl_vs_stop_at_close_per_env",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.pnl_vs_stop_at_close_per_env [alloc_episodes] f32 device-resident scratch — SP22 H6 vNext Phase A3 (2026-05-13) per-env trade-close P&L ratio vs `plan_stop × equity`. Companion to `pnl_vs_target_at_close_per_env` — same segment_complete producer site, same FoldReset semantics, same NULL-tolerant kernel arg pattern. Value semantics: `plan_isv[PLAN_ISV_PNL_VS_STOP]` (the local plan_isv value already computed at line ~877 from `-f_unrealized_pnl / (plan_stop × f_equity + 1e-6f)` clamped [-2, +2]). Consumer (eventual): `trade_outcome_label_kernel.cu`'s `pnl_vs_stop_at_close` arg — `≥ 1.0` predicate classifies as `Stop` (label 1). When neither pvt nor pvs ≥ 1.0 the kernel emits `Timeout` (label 2). FoldReset sentinel 0.0; reset path: `cudarc::driver::CudaStream::memset_zeros`.",
            },
            // SP22 H6 vNext Phase C cache + Phase B5b concat input — both
            // collector-side device buffers used by the K=3 trade-outcome
            // head's rollout-step launch. Stale-read risk differs (true
            // for `prev_aux_outcome_probs` which feeds state[121..124) at
            // step start; cleanliness-only for `exp_aux_to_input_buf`
            // which is written-before-read every step). Both registered
            // for FoldReset to satisfy `feedback_registry_entries_need_
            // dispatch_arms` discipline + match the per-fold reset
            // ergonomics of the rest of the K=3 head pipeline.
            RegistryEntry {
                name: "prev_aux_outcome_probs",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.prev_aux_outcome_probs [alloc_episodes × AUX_OUTCOME_K=3] f32 device-resident cache — SP22 H6 vNext Phase C (2026-05-14) per-env K=3 trade-outcome softmax cache. Producer: `aux_outcome_softmax_to_per_env_kernel` (end-of-step, reads `exp_aux_to_softmax_buf`). Consumer: `experience_state_gather` start-of-next-step, populates `state[AUX_OUTCOME_PROFIT_INDEX..AUX_OUTCOME_TIMEOUT_INDEX+1) = [121, 122, 123]`. FoldReset sentinel 0.0 across all `alloc_episodes × 3` slots — TRUE stale-read risk if previous fold's softmax probs leak into the new fold's step-0 state gather (would inject prior-fold's K=3 distribution into the new fold's first state slots, polluting the first batch's training signal). Reset path: `cudarc::driver::CudaStream::memset_zeros` on the `CudaSlice<f32>` (device-resident, no host buffer to fill). Per `pearl_first_observation_bootstrap`: the 0.0 cold-start reads as 'no Profit/Stop/Timeout signal' on step 0; the per-env producer then writes real K=3 softmax probs starting step 1.",
            },
            RegistryEntry {
                name: "exp_aux_to_input_buf",
                category: ResetCategory::FoldReset,
                description: "GpuExperienceCollector.exp_aux_to_input_buf [alloc_episodes × (SH2 + PLAN_PARAM_DIM) = N × 262] f32 device-resident input buffer — SP22 H6 vNext Phase B5b (2026-05-14) plan-conditioned input for the rollout-step K=3 forward. Producer: `aux_to_input_concat_kernel` (every rollout step, writes ALL 262 columns from `exp_h_s2_aux[N, 256]` + `exp_plan_params[N, 6]`). Consumer: `aux_trade_outcome_forward` (same step, reads as `[N, 262]` GEMM input). Stale-read risk: NONE in steady state (every step's concat overwrites the full buffer before the forward reads it). FoldReset is included for registry-discipline parity with the rest of the K=3 pipeline (per `feedback_registry_entries_need_dispatch_arms`) and to guarantee a clean baseline at fold boundary if a future change ever turns this from write-every-step into a conditional write. Sentinel 0.0; reset path: `cudarc::driver::CudaStream::memset_zeros`.",
            },
            // ── Alpha trading system block (slots 539..=548, 2026-05-15) ──
            // Durable system-scoped infrastructure per `alpha_isv_slots.rs`.
            // 4 SoftReset diagnostics (539-542) + 3 FoldReset controllers
            // (543, 545, 546) + 3 TrainingPersist anchors (544, 547, 548).
            // TrainingPersist entries are set ONCE per fold by the host and
            // do not need dispatch arms in `reset_named_state` (the registry
            // test at line ~2325 filters them out before the dispatch check).
            RegistryEntry {
                name: "alpha_q_spread_ema",
                category: ResetCategory::SoftReset { decay_bars: 1000 },
                description: "ISV[Q_SPREAD_EMA_INDEX=539] — alpha trading system kill-criterion #1 (Phase E.1). EMA of `std(Q, axis=action) / |mean(Q)|` averaged across the rollout batch — measures whether the policy's Q-values have meaningful action-spread (vs collapsed to a constant). Producer (eventual, Phase E.1): `alpha_kill_criteria.cu` kernel reading per-rollout Q-values, Pearl A + Pearl D Wiener-α with α-floor 0.4 (controller co-adapts with policy per `pearl_wiener_alpha_floor_for_nonstationary`). Consumer: Phase E.1 kill-criteria gate (training proceeds only if EMA > 0.05 past epoch 10). Cold-start sentinel 0.0; SoftReset decay 1000 bars — allows a fading carry-over across rollouts but resets cleanly at fold boundary to avoid stale-regime contamination. Reset path: `write_isv_signal_at(539, 0.0)` + Wiener state zero (handled by the producer's first-observation bootstrap at next launch).",
            },
            RegistryEntry {
                name: "alpha_action_entropy_ema",
                category: ResetCategory::SoftReset { decay_bars: 1000 },
                description: "ISV[ACTION_ENTROPY_EMA_INDEX=540] — alpha trading system kill-criterion #2 (Phase E.1). EMA of `H(action_dist)` from the rollout's action histogram — measures whether the policy explores meaningfully (vs deterministic-collapse to one action). Producer (eventual): `alpha_kill_criteria.cu`, Pearl A bootstrap + fixed-α 0.01 (a stable per-rollout entropy doesn't need adaptive α; SP-chain pattern matches `REWARD_CAP_EMA_ALPHA=0.01` per `sp14_isv_slots.rs:158`). Consumer: kill-criteria gate (entropy > 0.5·ln(9) past epoch 10). Cold-start sentinel 0.0; SoftReset 1000 bars — same rationale as 539. The 9 in `ln(9)` is `N_ACTIONS` from `crates/ml/src/env/action_space.rs`.",
            },
            RegistryEntry {
                name: "alpha_return_vs_random_ema",
                category: ResetCategory::SoftReset { decay_bars: 1000 },
                description: "ISV[RETURN_VS_RANDOM_EMA_INDEX=541] — alpha trading system kill-criterion #3 (Phase E.1). EMA of `(rollout_R − random_R) / σ_random` where `random_R` and `σ_random` are read from slots 547/548 (`RANDOM_BASELINE_MEAN_INDEX` and `RANDOM_BASELINE_STD_INDEX`) populated once per fold by the Phase E.0 baseline computation. Measures signed σ-distance of the trained policy's reward distribution from the random-uniform baseline — kill if not > 2.0 past epoch 10. Producer (eventual): `alpha_kill_criteria.cu`, Pearl A bootstrap + fixed-α 0.05 (per-rollout signal-to-noise warrants a slightly faster EMA than entropy). Consumer: kill-criteria gate. Cold-start sentinel 0.0; SoftReset 1000 bars.",
            },
            RegistryEntry {
                name: "alpha_early_q_movement_ema",
                category: ResetCategory::SoftReset { decay_bars: 1000 },
                description: "ISV[EARLY_Q_MOVEMENT_EMA_INDEX=542] — alpha trading system kill-criterion #4 (Phase E.1). EMA of `|Q(s_early) − Q_init| / |Q_init|` measuring whether terminal-reward signal at H=6000 propagates back to early-step Q-values (the diagnostic against pure TD-bootstrap failure — see `pearl_horizon_decay_falsifies_long_horizon_stateless` for the upstream finding). Producer (eventual): `alpha_kill_criteria.cu` per-epoch (not per-step), reads a held-out set of early-step states + the snapshot of init-Q values. Consumer: kill-criteria gate (early movement > 0.01 past epoch 10). Cold-start sentinel 0.0; SoftReset 1000 bars — but in practice this slot is read epoch-by-epoch so the decay rarely matters.",
            },
            RegistryEntry {
                name: "alpha_stacker_threshold",
                category: ResetCategory::FoldReset,
                description: "ISV[STACKER_THRESHOLD_INDEX=543] — alpha trading system stacker-confidence threshold for trade eligibility. Engagement-rate self-correction per `pearl_engagement_rate_self_correction` — driven from `TRADE_RATE_OBSERVED_EMA_INDEX=545` vs `TRADE_RATE_TARGET_INDEX=544`: when observed > target, raise threshold (be pickier, fewer trades); when observed < target, lower threshold (trade more). Producer (eventual, Phase E.2): `stacker_threshold_controller.cu`, bidirectional ramp with step k=0.01, bounded [0.0, 0.5]. Consumer: Phase E execution-env step (trade eligibility gate). FoldReset sentinel 0.0 — first-observation bootstrap: when the controller first runs, it sees observed_ema=0 (no trades yet) and target=0.08 (anchor) → raises threshold from 0.0 toward 0.08; Pearl A correctness preserved.",
            },
            RegistryEntry {
                name: "alpha_trade_rate_target",
                category: ResetCategory::TrainingPersist,
                description: "ISV[TRADE_RATE_TARGET_INDEX=544] — alpha trading system trade-rate target (anchor for the engagement-rate self-correction controller at slot 543). TrainingPersist because this is a *hyperparameter anchor* set ONCE per training run by the host at training start (default 0.08 = 8% of decisions emit a trade). NOT updated by any GPU kernel; the controller READS this slot but never writes it. Reset path: handled by host at training start, no dispatch arm in `reset_named_state`. Per the existing TrainingPersist pattern (see SP4 `GRAD_CLIP_BOUND_INDEX` and Kelly priors), TrainingPersist anchors do not appear in the dispatch match — the registry test at line 2325 ignores them.",
            },
            RegistryEntry {
                name: "alpha_trade_rate_observed_ema",
                category: ResetCategory::FoldReset,
                description: "ISV[TRADE_RATE_OBSERVED_EMA_INDEX=545] — alpha trading system observed trade-rate EMA. Driven from per-rollout trade-count / decision-count. Producer (eventual, Phase E.2): `stacker_threshold_controller.cu`, Pearl A bootstrap + Welford accumulator with α-floor 0.4 (controller co-adapts with policy → Wiener-α would collapse to 0 per `pearl_wiener_alpha_floor_for_nonstationary`, so we use the SP16 T3 pattern). Consumer: same kernel reads this slot to compute the error vs target (544) before updating threshold (543). FoldReset sentinel 0.0 — first observation bootstraps from the first rollout's trade-rate measurement.",
            },
            RegistryEntry {
                name: "alpha_stacker_kelly_attenuation",
                category: ResetCategory::FoldReset,
                description: "ISV[STACKER_KELLY_ATTENUATION_INDEX=546] — alpha trading system Kelly attenuation factor. Multiplied with the existing cross-fold-persistent `KELLY_F_SMOOTH_INDEX=280` before the contract-cap is applied: `effective_kelly_fraction = max(0.1, min(1.0, alpha_stacker_kelly_attenuation × kelly_f_smooth))`. Driven from realized rollout Sharpe vs target — Sharpe above target raises attenuation toward 1.0 (use more Kelly), below target lowers toward floor 0.1 (defensive). Producer (eventual): `stacker_threshold_controller.cu` co-located with the threshold update, step 0.005 per rollout, bounded [0.1, 1.0] per `pearl_blend_formulas_must_have_permanent_floor` — the 0.1 floor prevents Kelly→0 deadlock if Sharpe goes negative. Consumer: existing Kelly composition site in `trade_physics.cuh::apply_kelly_sizing`. FoldReset sentinel 0.0 — Pearl A bootstrap: first rollout's Sharpe sets the initial attenuation directly. Distinct from `KELLY_F_SMOOTH_INDEX=280` which is cross-fold-persistent (per `pearl_kelly_cap_signal_driven_floors`); this slot is fold-local because the attenuation logic is per-policy-instance, not per-population.",
            },
            RegistryEntry {
                name: "alpha_random_baseline_mean",
                category: ResetCategory::TrainingPersist,
                description: "ISV[RANDOM_BASELINE_MEAN_INDEX=547] — alpha trading system random-uniform-policy baseline reward mean. TrainingPersist because computed ONCE per fold by the host (the Phase E.0 baseline example runs N=10,000 episodes with a uniform random action policy and records the mean terminal reward). Read by `alpha_return_vs_random_ema` (slot 541) producer to compute the σ-distance kill criterion. No GPU producer; host writes via `write_isv_signal_at`. No dispatch arm in `reset_named_state` (TrainingPersist convention).",
            },
            RegistryEntry {
                name: "alpha_random_baseline_std",
                category: ResetCategory::TrainingPersist,
                description: "ISV[RANDOM_BASELINE_STD_INDEX=548] — alpha trading system random-uniform-policy baseline reward standard deviation. Companion to slot 547. TrainingPersist with same rationale — host writes once per fold from the baseline example. Read by the kill-criteria producer to normalize the trained-policy reward distribution into σ-units. No dispatch arm.",
            },
        ];
        Self { entries }
    }

    /// Look up a state's category by name. Returns `None` for unknown names
    /// (caller should assert Some before use to catch typos).
    pub fn category(&self, name: &str) -> Option<ResetCategory> {
        self.entries.iter().find(|e| e.name == name).map(|e| e.category)
    }

    /// Iterator over all entries with `FoldReset` category.
    /// Used by the fold-boundary reset logic.
    pub fn fold_reset_entries(&self) -> impl Iterator<Item = &RegistryEntry> {
        self.entries.iter().filter(|e| e.category == ResetCategory::FoldReset)
    }

    /// Iterator over all entries with `WindowReset` category.
    pub fn window_reset_entries(&self) -> impl Iterator<Item = &RegistryEntry> {
        self.entries.iter().filter(|e| e.category == ResetCategory::WindowReset)
    }

    /// Iterator over all entries with `SoftReset` category.
    pub fn soft_reset_entries(&self) -> impl Iterator<Item = &RegistryEntry> {
        self.entries.iter().filter(|e| matches!(e.category, ResetCategory::SoftReset { .. }))
    }

    /// All entries (debug/diagnostic dump).
    pub fn all(&self) -> &[RegistryEntry] {
        &self.entries
    }
}

impl Default for StateResetRegistry {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn registry_classifies_known_state() {
        let r = StateResetRegistry::new();
        assert_eq!(r.category("kelly_stats"), Some(ResetCategory::FoldReset));
        assert_eq!(r.category("isv_grad_balance_targets"), Some(ResetCategory::SoftReset { decay_bars: 500 }));
        assert_eq!(r.category("network_params"), Some(ResetCategory::TrainingPersist));
        assert_eq!(r.category("ISV_LAYOUT_FINGERPRINT"), Some(ResetCategory::SchemaContract));
    }

    #[test]
    fn registry_fold_reset_iterates_only_fold_reset_entries() {
        let r = StateResetRegistry::new();
        let names: Vec<&str> = r.fold_reset_entries().map(|e| e.name).collect();
        assert!(names.contains(&"kelly_stats"));
        assert!(!names.contains(&"network_params"));
    }

    #[test]
    fn registry_unknown_name_returns_none() {
        let r = StateResetRegistry::new();
        assert_eq!(r.category("nonexistent_state"), None);
    }

    /// Contract test: every FoldReset/SoftReset entry in StateResetRegistry::new()
    /// must have a corresponding match arm in reset_named_state. Catches the
    /// "add registry entry, forget dispatch arm → runtime panic at fold boundary"
    /// bug pattern (occurred twice: SP5 Layer A #281, SP7 T7 commit 6e479c55c).
    ///
    /// Source-introspection design — no production-code change. The test extracts
    /// the reset_named_state function body via brace-balance walk, then checks
    /// that each FoldReset/SoftReset entry name appears as a string literal inside
    /// that body.
    #[test]
    fn every_fold_and_soft_reset_entry_has_dispatch_arm() {
        let dispatch_src = include_str!("trainer/training_loop.rs");

        // Extract reset_named_state body: find fn signature, then match-block.
        let fn_start = dispatch_src
            .find("pub(crate) fn reset_named_state")
            .expect("reset_named_state not found in training_loop.rs");
        let after_fn = &dispatch_src[fn_start..];

        // Find `match name {` inside the function body.
        let match_rel = after_fn
            .find("match name {")
            .expect("match name { not found in reset_named_state");
        let match_start_abs = fn_start + match_rel;

        // Walk braces to extract the match block (from `match name {` to its
        // closing `}`), so we only search within the dispatch, not the rest of
        // the file.
        let match_src = &dispatch_src[match_start_abs..];
        let body = {
            let mut depth: i32 = 0;
            let mut end = match_src.len();
            for (i, ch) in match_src.char_indices() {
                match ch {
                    '{' => depth += 1,
                    '}' => {
                        depth -= 1;
                        if depth == 0 {
                            end = i + 1;
                            break;
                        }
                    }
                    _ => {}
                }
            }
            &match_src[..end]
        };

        let registry = StateResetRegistry::new();
        // FoldReset and SoftReset (any decay_bars) both dispatch through
        // reset_named_state. WindowReset/TrainingPersist/SchemaContract do not.
        let entries_needing_dispatch: Vec<&RegistryEntry> = registry
            .all()
            .iter()
            .filter(|e| matches!(
                e.category,
                ResetCategory::FoldReset | ResetCategory::SoftReset { .. }
            ))
            .collect();

        let mut missing: Vec<&str> = Vec::new();
        for entry in &entries_needing_dispatch {
            let needle = format!("\"{}\"", entry.name);
            if !body.contains(needle.as_str()) {
                missing.push(entry.name);
            }
        }

        assert!(
            missing.is_empty(),
            "Registry entries with no dispatch arm in reset_named_state ({} total, {} missing): {:?}\n\
             These will panic at fold-boundary with 'unknown name' MLError.\n\
             Add a match arm in trainer/training_loop.rs::reset_named_state.",
            entries_needing_dispatch.len(),
            missing.len(),
            missing
        );
    }

    /// Lock SP18 v2 Pre-Phase Task PP.3 + ISV-adaptive shrink-and-perturb
    /// close-out + SP19 producer-side multi-horizon reward blend reservations:
    /// 27 fold-reset entries land for the combined Hold-attractor fix slots
    /// [483..507) plus the SP19 reservations [507..510). 10 D-leg + 12 B-leg
    /// + 2 shrink-and-perturb + 3 SP19 reservation. Asserts each by name is
    /// present with FoldReset category and a description marker matching
    /// its leg.
    #[test]
    fn sp18_fold_reset_entries_present() {
        let r = StateResetRegistry::new();
        let by_name: std::collections::HashMap<&str, &RegistryEntry> =
            r.all().iter().map(|e| (e.name, e)).collect();

        // 27 expected SP18 + SP19 entries — D-leg 10 + B-leg 12 + shrink-and-perturb 2 + SP19 3.
        let expected: &[(&str, &str)] = &[
            // D-leg [483..493) — 10 slots
            ("sp18_hold_reward_pos_cap",          "SP18 D-leg"),
            ("sp18_hold_reward_neg_cap",          "SP18 D-leg"),
            ("sp18_hold_reward_decomp_diag",      "SP18 D-leg"),
            ("sp18_hold_opp_cost_fire_rate_ema",  "SP18 D-leg"),
            ("sp18_hrc_target_mean",              "SP18 D-leg"),
            ("sp18_hrc_target_m2",                "SP18 D-leg"),
            ("sp18_hrc_diff_mean",                "SP18 D-leg"),
            ("sp18_hrc_diff_m2",                  "SP18 D-leg"),
            ("sp18_hrc_prev_target",              "SP18 D-leg"),
            ("sp18_hrc_sample_count",             "SP18 D-leg"),
            // B-leg [493..505) — 12 slots
            ("sp18_td_error_mag_ema",             "SP18 B-leg"),
            ("sp18_q_next_target_p99",            "SP18 B-leg"),
            ("sp18_q_next_minus_reward_p99",      "SP18 B-leg"),
            ("sp18_v_share_trend_diag",           "SP18 B-leg"),
            ("sp18_popart_reset_flag",            "SP18 B-leg"),
            ("sp18_tdb_target_mean",              "SP18 B-leg"),
            ("sp18_tdb_target_m2",                "SP18 B-leg"),
            ("sp18_tdb_diff_mean",                "SP18 B-leg"),
            ("sp18_tdb_diff_m2",                  "SP18 B-leg"),
            ("sp18_tdb_prev_target",              "SP18 B-leg"),
            ("sp18_tdb_sample_count",             "SP18 B-leg"),
            ("sp18_b_leg_reserved",               "SP18 B-leg"),
            // shrink-and-perturb [505..507) — 2 slots
            ("sp18_shrink_alpha_adaptive",        "SP18 v2 adaptive shrink factor"),
            ("sp18_shrink_sigma_adaptive",        "SP18 v2 adaptive noise scale"),
            // SP19 producer-side multi-horizon reward blend reservations [507..510) — 3 slots
            ("sp19_reward_horizon_weight_1bar",   "SP19 Path (B) reservation"),
            ("sp19_reward_horizon_weight_5bar",   "SP19 Path (B) reservation"),
            ("sp19_reward_horizon_weight_30bar",  "SP19 Path (B) reservation"),
        ];

        assert_eq!(expected.len(), 27, "expected 27 SP18+SP19 entries (10 D-leg + 12 B-leg + 2 shrink-and-perturb + 3 SP19 reservation)");

        for (name, leg_marker) in expected {
            let entry = by_name.get(name).unwrap_or_else(|| {
                panic!(
                    "SP18 v2 PP.3 / SP19: registry missing entry '{}'. Add a `RegistryEntry` to \
                     `StateResetRegistry::new()` AND a dispatch arm in \
                     `trainer/training_loop.rs::reset_named_state` (else \
                     `every_fold_and_soft_reset_entry_has_dispatch_arm` fires too).",
                    name
                )
            });
            assert_eq!(
                entry.category,
                ResetCategory::FoldReset,
                "SP18/SP19 entry '{}' must be FoldReset (got {:?})", name, entry.category
            );
            assert!(
                entry.description.contains(leg_marker),
                "SP18/SP19 entry '{}' description must contain '{}'; got: {}",
                name, leg_marker, entry.description
            );
        }
    }
}

#[cfg(test)]
mod sp20_registry_tests {
    use super::*;

    #[test]
    fn sp20_isv_slots_registered_with_sentinel_zero() {
        let registry = StateResetRegistry::new();
        for slot_name in [
            "loss_cap",
            "alpha_ema",
            "wr_ema",
            "hold_cost_scale",
            "target_hold_pct",
            "hold_pct_ema",
            "hold_reward_ema",
            "n_step",
            "aux_conf_threshold",
            "aux_gate_temp",
        ] {
            let entry = registry
                .entries
                .iter()
                .find(|e| e.name == slot_name)
                .unwrap_or_else(|| {
                    panic!("SP20 slot {} not registered in StateResetRegistry", slot_name)
                });
            assert_eq!(
                entry.category,
                ResetCategory::FoldReset,
                "SP20 slot {} must be FoldReset (got {:?})",
                slot_name,
                entry.category
            );
        }
    }

    /// SP20 Phase 2 Task 2.0: `label_at_open_per_env` MUST be registered as
    /// FoldReset so the new fold's first `entering_trade` branch fully
    /// re-populates from the new fold's aux head (preventing stale label
    /// leakage across folds — each fold has independent aux head
    /// calibration). Description MUST mention SP20 Phase 2 + Task 2.0 +
    /// `entering_trade` + `is_close` so wire-up audits have a stable
    /// search anchor.
    #[test]
    fn sp20_label_at_open_per_env_registered_fold_reset() {
        let registry = StateResetRegistry::new();
        let entry = registry
            .entries
            .iter()
            .find(|e| e.name == "label_at_open_per_env")
            .expect("label_at_open_per_env must be registered in StateResetRegistry");
        assert_eq!(
            entry.category,
            ResetCategory::FoldReset,
            "label_at_open_per_env must be FoldReset (got {:?})",
            entry.category
        );
        assert!(
            entry.description.contains("SP20 Phase 2"),
            "description must reference 'SP20 Phase 2'; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("entering_trade"),
            "description must reference 'entering_trade' producer site; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("is_close"),
            "description must reference 'is_close' consumer site; got: {}",
            entry.description
        );
    }

    /// SP20 Phase 2 Task 2.2-fix: `is_win_per_env` MUST be registered
    /// as FoldReset so the new fold's first trade-close fully re-
    /// populates from the new fold's `segment_return > 0` predicate
    /// (preventing stale win-flag leakage into the new fold's WR_EMA
    /// bootstrap). Description MUST mention SP20 Phase 2 + Task
    /// 2.2-fix + `segment_complete` (producer) +
    /// `sp20_aggregate_inputs_kernel` (consumer) so wire-up audits
    /// have a stable search anchor.
    #[test]
    fn sp20_is_win_per_env_registered_fold_reset() {
        let registry = StateResetRegistry::new();
        let entry = registry
            .entries
            .iter()
            .find(|e| e.name == "is_win_per_env")
            .expect("is_win_per_env must be registered in StateResetRegistry");
        assert_eq!(
            entry.category,
            ResetCategory::FoldReset,
            "is_win_per_env must be FoldReset (got {:?})",
            entry.category
        );
        assert!(
            entry.description.contains("SP20 Phase 2"),
            "description must reference 'SP20 Phase 2'; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("Task 2.2-fix"),
            "description must reference 'Task 2.2-fix'; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("segment_complete"),
            "description must reference 'segment_complete' producer site; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("sp20_aggregate_inputs_kernel"),
            "description must reference the aggregation-kernel consumer; got: {}",
            entry.description
        );
    }

    /// SP20 Phase 2 Task 2.2: `alpha_per_env` MUST be registered as
    /// FoldReset so the new fold's first trade-close fully re-populates
    /// from the new fold's reward calculation (preventing stale alpha
    /// leakage into the new fold's ALPHA_EMA bootstrap). Description
    /// MUST mention SP20 Phase 2 + Task 2.2 + `is_close` (producer) +
    /// `sp20_aggregate_inputs_kernel` (consumer) so wire-up audits
    /// have a stable search anchor.
    #[test]
    fn sp20_alpha_per_env_registered_fold_reset() {
        let registry = StateResetRegistry::new();
        let entry = registry
            .entries
            .iter()
            .find(|e| e.name == "alpha_per_env")
            .expect("alpha_per_env must be registered in StateResetRegistry");
        assert_eq!(
            entry.category,
            ResetCategory::FoldReset,
            "alpha_per_env must be FoldReset (got {:?})",
            entry.category
        );
        assert!(
            entry.description.contains("SP20 Phase 2"),
            "description must reference 'SP20 Phase 2'; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("is_close"),
            "description must reference 'is_close' producer site; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("sp20_aggregate_inputs_kernel"),
            "description must reference the aggregation-kernel consumer; got: {}",
            entry.description
        );
    }

    /// SP20 Phase 3 Task 3.2: `hold_baseline_buffer` MUST be registered
    /// as FoldReset so the new fold's first trade-close summation reads
    /// only this fold's per-bar writes — no stale bars leak across
    /// folds. Description MUST mention SP20 Phase 3 + Task 3.2 +
    /// per-bar branches (producer) + segment_complete (consumer) so
    /// wire-up audits have a stable search anchor.
    #[test]
    fn sp20_hold_baseline_buffer_registered_fold_reset() {
        let registry = StateResetRegistry::new();
        let entry = registry
            .entries
            .iter()
            .find(|e| e.name == "hold_baseline_buffer")
            .expect("hold_baseline_buffer must be registered in StateResetRegistry");
        assert_eq!(
            entry.category,
            ResetCategory::FoldReset,
            "hold_baseline_buffer must be FoldReset (got {:?})",
            entry.category
        );
        assert!(
            entry.description.contains("SP20 Phase 3"),
            "description must reference 'SP20 Phase 3'; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("Task 3.2"),
            "description must reference 'Task 3.2'; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("per-bar branches"),
            "description must reference 'per-bar branches' producer site; got: {}",
            entry.description
        );
        assert!(
            entry.description.contains("segment_complete")
                || entry.description.contains("trade-close"),
            "description must reference the segment_complete / trade-close consumer; got: {}",
            entry.description
        );
    }
}
