From 4249ebc961889734e3ea112bb73fb8ba222b4d2f Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sat, 9 May 2026 18:17:38 +0200 Subject: [PATCH] feat(sp20): register 10 ISV slots in StateResetRegistry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sentinel = 0.0 per pearl_first_observation_bootstrap. First observation of each EMA replaces the sentinel directly, no blending. Slots [510..520): - loss_cap (510): adaptive loss cap for reward clamp - alpha_ema (511): Wiener-α EMA for loss_cap producer - wr_ema (512): win-rate EMA driving loss_cap adaptive ramp - hold_cost_scale (513): hold penalty cost multiplier - target_hold_pct (514): hold-engagement target - hold_pct_ema (515): hold-engagement EMA - hold_reward_ema (516): hold-action reward EMA - n_step (517): multi-step TD horizon adapter - aux_conf_threshold (518): auxiliary task confidence threshold - aux_gate_temp (519): auxiliary task gating temperature --- .../src/trainers/dqn/state_reset_registry.rs | 99 +++++++++++++++++++ docs/isv-slots.md | 3 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/crates/ml/src/trainers/dqn/state_reset_registry.rs b/crates/ml/src/trainers/dqn/state_reset_registry.rs index 2888cf3c4..ef398e5f2 100644 --- a/crates/ml/src/trainers/dqn/state_reset_registry.rs +++ b/crates/ml/src/trainers/dqn/state_reset_registry.rs @@ -1,6 +1,13 @@ //! 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. +use crate::cuda_pipeline::sp14_isv_slots::{ + LOSS_CAP_INDEX, ALPHA_EMA_INDEX, WR_EMA_INDEX, + HOLD_COST_SCALE_INDEX, TARGET_HOLD_PCT_INDEX, HOLD_PCT_EMA_INDEX, + HOLD_REWARD_EMA_INDEX, N_STEP_INDEX, + AUX_CONF_THRESHOLD_INDEX, AUX_GATE_TEMP_INDEX, +}; + /// 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. @@ -2031,6 +2038,61 @@ impl StateResetRegistry { 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", + }, ]; Self { entries } } @@ -2248,3 +2310,40 @@ mod tests { } } } + +#[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 + ); + } + } +} diff --git a/docs/isv-slots.md b/docs/isv-slots.md index c1eece75a..e6f306471 100644 --- a/docs/isv-slots.md +++ b/docs/isv-slots.md @@ -497,7 +497,8 @@ work stream and establishes the slot base for upcoming components: **Files touched (Pre.2 atomic):** - `crates/ml/src/cuda_pipeline/sp14_isv_slots.rs` — 10 `pub const *_INDEX` constants (at the top level, before the test module) + SP20_SLOT_BASE (510) + SP20_SLOT_END (520) constants + 1 regression test (`sp20_isv_slots_reserved_510_to_520`) verifying all 10 slot indices and ISV_TOTAL_DIM=520 - `crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs` — `ISV_TOTAL_DIM: 510 → 520`, `layout_fingerprint_seed()` extended with all 10 slot `name=index` entries + `ISV_TOTAL_DIM=520` marker (forces fingerprint hash bump → pre-SP20 checkpoints invalidated, greenfield OK) +- `crates/ml/src/trainers/dqn/state_reset_registry.rs` — Task Pre.3 registers all 10 SP20 slots with `FoldReset` category and sentinel=0.0 per `pearl_first_observation_bootstrap`; includes unit test `sp20_isv_slots_registered_with_sentinel_zero` -**Producers/consumers status:** Pre.2 lands the slot reservation only; all 10 slots are zero-initialized until subsequent SP20 phases land producers (per-epoch ISV seeds + GPU kernels) and consumer migration. Mirrors the SP4/SP5/SP11/SP15 pre-allocation pattern. +**Producers/consumers status:** Pre.2 lands the slot reservation only; Pre.3 registers in state reset machinery; all 10 slots are zero-initialized until subsequent SP20 phases land producers (per-epoch ISV seeds + GPU kernels) and consumer migration. Mirrors the SP4/SP5/SP11/SP15 pre-allocation pattern. **ISV_TOTAL_DIM:** 510 → 520 (Pre.2 adds 10 slots).