feat(sp20): register 10 ISV slots in StateResetRegistry

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
This commit is contained in:
jgrusewski
2026-05-09 18:17:38 +02:00
parent f5eed1fa79
commit 4249ebc961
2 changed files with 101 additions and 1 deletions

View File

@@ -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
);
}
}
}

View File

@@ -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).