diff --git a/crates/ml/src/cuda_pipeline/alpha_isv_slots.rs b/crates/ml/src/cuda_pipeline/alpha_isv_slots.rs new file mode 100644 index 000000000..407969e1c --- /dev/null +++ b/crates/ml/src/cuda_pipeline/alpha_isv_slots.rs @@ -0,0 +1,117 @@ +//! Alpha trading system ISV slot block. +//! +//! Reserves indices 539..=550 (12 slots, contiguous) for durable +//! infrastructure of the alpha trading system: stacker/execution-policy +//! diagnostics, controller anchors, and population baselines. Unlike the +//! SP4..SP22 slot files (which were per-iteration milestone-scoped), this +//! block is named for the *system* — these slots are intended to outlive +//! any individual Phase E/F/G milestone. +//! +//! Consumers read via the standard sentinel-bootstrap pattern: +//! `if isv[idx] <= ALPHA_SENTINEL + ALPHA_SENTINEL_EPS { fallback }`. +//! +//! Slot layout: +//! +//! | Index | Name | Role | Update cadence | Producer kernel | +//! |-------|------------------------------|--------------|-----------------|------------------------------------------| +//! | 539 | Q_SPREAD_EMA_INDEX | Diagnostic | per-rollout-step| phase_e_kill_criteria.cu | +//! | 540 | ACTION_ENTROPY_EMA_INDEX | Diagnostic | per-rollout-step| phase_e_kill_criteria.cu | +//! | 541 | RETURN_VS_RANDOM_EMA_INDEX | Diagnostic | per-trade-close | phase_e_kill_criteria.cu | +//! | 542 | EARLY_Q_MOVEMENT_EMA_INDEX | Diagnostic | per-epoch | phase_e_kill_criteria.cu | +//! | 543 | STACKER_THRESHOLD_INDEX | Controller | per-rollout-step| stacker_threshold_controller.cu | +//! | 544 | TRADE_RATE_TARGET_INDEX | Anchor | static | host init | +//! | 545 | TRADE_RATE_OBSERVED_EMA_INDEX| Diagnostic | per-rollout-step| stacker_threshold_controller.cu | +//! | 546 | STACKER_KELLY_ATTENUATION_IX | Controller | per-trade-close | stacker_threshold_controller.cu | +//! | 547 | RANDOM_BASELINE_MEAN_INDEX | Anchor | per-fold | host computes once per fold | +//! | 548 | RANDOM_BASELINE_STD_INDEX | Anchor | per-fold | host computes once per fold | +//! | 549 | (reserved spare) | — | — | — | +//! | 550 | (reserved spare) | — | — | — | +//! +//! Reservation discipline (per the alpha-system ISV research memo): slots 549..550 +//! are intentionally unused at first-commit to absorb growth without bumping +//! `ISV_TOTAL_DIM` again. Add new alpha-system slots HERE first, not by extending +//! past 550 ad-hoc. + +pub const ALPHA_ISV_BLOCK_LO: usize = 539; +pub const ALPHA_ISV_BLOCK_HI: usize = 550; // inclusive upper + +// Diagnostics (read-only for circuit breakers; not controllers) +pub const Q_SPREAD_EMA_INDEX: usize = 539; +pub const ACTION_ENTROPY_EMA_INDEX: usize = 540; +pub const RETURN_VS_RANDOM_EMA_INDEX: usize = 541; +pub const EARLY_Q_MOVEMENT_EMA_INDEX: usize = 542; + +// Stacker-threshold controller (engagement-rate self-correction) +pub const STACKER_THRESHOLD_INDEX: usize = 543; +pub const TRADE_RATE_TARGET_INDEX: usize = 544; +pub const TRADE_RATE_OBSERVED_EMA_INDEX: usize = 545; +pub const STACKER_KELLY_ATTENUATION_INDEX: usize = 546; + +// Random-uniform baseline (computed once per fold; used by kill criterion 541) +pub const RANDOM_BASELINE_MEAN_INDEX: usize = 547; +pub const RANDOM_BASELINE_STD_INDEX: usize = 548; + +// Sentinels: zero by convention. Fallbacks use the first-observation +// bootstrap pattern (see pearl_first_observation_bootstrap.md). +pub const ALPHA_SENTINEL: f32 = 0.0; +pub const ALPHA_SENTINEL_EPS: f32 = 1e-9; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_block_bounds_consistent() { + assert!(ALPHA_ISV_BLOCK_HI >= ALPHA_ISV_BLOCK_LO); + let block_size = ALPHA_ISV_BLOCK_HI - ALPHA_ISV_BLOCK_LO + 1; + assert_eq!(block_size, 12, "alpha-system reserved 12 contiguous slots"); + } + + #[test] + fn test_all_indices_inside_block() { + let indices = [ + Q_SPREAD_EMA_INDEX, + ACTION_ENTROPY_EMA_INDEX, + RETURN_VS_RANDOM_EMA_INDEX, + EARLY_Q_MOVEMENT_EMA_INDEX, + STACKER_THRESHOLD_INDEX, + TRADE_RATE_TARGET_INDEX, + TRADE_RATE_OBSERVED_EMA_INDEX, + STACKER_KELLY_ATTENUATION_INDEX, + RANDOM_BASELINE_MEAN_INDEX, + RANDOM_BASELINE_STD_INDEX, + ]; + for &i in &indices { + assert!(i >= ALPHA_ISV_BLOCK_LO && i <= ALPHA_ISV_BLOCK_HI, + "slot {i} out of alpha-system block"); + } + } + + #[test] + fn test_indices_unique() { + let indices = [ + Q_SPREAD_EMA_INDEX, + ACTION_ENTROPY_EMA_INDEX, + RETURN_VS_RANDOM_EMA_INDEX, + EARLY_Q_MOVEMENT_EMA_INDEX, + STACKER_THRESHOLD_INDEX, + TRADE_RATE_TARGET_INDEX, + TRADE_RATE_OBSERVED_EMA_INDEX, + STACKER_KELLY_ATTENUATION_INDEX, + RANDOM_BASELINE_MEAN_INDEX, + RANDOM_BASELINE_STD_INDEX, + ]; + let mut sorted: Vec = indices.to_vec(); + sorted.sort(); + sorted.dedup(); + assert_eq!(sorted.len(), indices.len(), "duplicate slot index"); + } + + #[test] + fn test_total_dim_covers_block() { + // The parent ISV_TOTAL_DIM must be at least ALPHA_ISV_BLOCK_HI + 1. + use crate::cuda_pipeline::gpu_dqn_trainer::ISV_TOTAL_DIM; + assert!(ISV_TOTAL_DIM > ALPHA_ISV_BLOCK_HI, + "ISV_TOTAL_DIM ({ISV_TOTAL_DIM}) must exceed ALPHA_ISV_BLOCK_HI ({ALPHA_ISV_BLOCK_HI})"); + } +} diff --git a/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs b/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs index 86b441d41..19c856800 100644 --- a/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs +++ b/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs @@ -2744,7 +2744,7 @@ const ISV_NETWORK_DIM: usize = 23; /// (and the C-side mirrors in `state_layout.cuh`). Bump this constant in the /// SAME commit that adds the new range, and update `layout_fingerprint_seed` /// to register the new slot names. -pub(crate) const ISV_TOTAL_DIM: usize = 539; // SP22 H6 vNext Phase F-3 (2026-05-14) adds 1 slot [538..539) for AUX_TRADE_OUTCOME_CE_EMA_INDEX (K=3 trade-outcome head's sparse-CE EMA — observability of head training during smoke). SP22 H6 Phase 3 (2026-05-13) adds 2 slots [536..538) for the aux→policy bypass: REWARD_AUX_ALIGN_EMA_INDEX (7th reward component EMA, anchor for SP11 controller's w_aux_align) and SP22_AUX_ALIGN_SCALE_INDEX (controller-emitted adaptive scale_β consumed by β producers at training and eval). SP21 Phase 7.5 added 8 slots [528..536) for CURRICULUM_WEIGHT_{0..8} (per_insert_pa per-segment priority boost); Phase 7 added 1 slot [527..528); Phase 5+6 added 2 slots [525..527); Phase 4 added 4 slots [521..525); Phase 3 added 1 slot [520..521) +pub(crate) const ISV_TOTAL_DIM: usize = 551; // Alpha trading system (2026-05-15, Phase E intro commit) reserves 12 slots [539..551) for durable infrastructure: diagnostics + stacker-threshold controller + random-baseline anchors. 2 slots [549..551) intentionally spare to absorb growth. See alpha_isv_slots.rs. SP22 H6 vNext Phase F-3 (2026-05-14) added 1 slot [538..539) for AUX_TRADE_OUTCOME_CE_EMA_INDEX (K=3 trade-outcome head's sparse-CE EMA — observability of head training during smoke). SP22 H6 Phase 3 (2026-05-13) added 2 slots [536..538) for the aux→policy bypass: REWARD_AUX_ALIGN_EMA_INDEX (7th reward component EMA, anchor for SP11 controller's w_aux_align) and SP22_AUX_ALIGN_SCALE_INDEX (controller-emitted adaptive scale_β consumed by β producers at training and eval). SP21 Phase 7.5 added 8 slots [528..536) for CURRICULUM_WEIGHT_{0..8} (per_insert_pa per-segment priority boost); Phase 7 added 1 slot [527..528); Phase 5+6 added 2 slots [525..527); Phase 4 added 4 slots [521..525); Phase 3 added 1 slot [520..521) /// Legacy alias preserved for call sites that haven't been audited for the /// network-vs-total split. New code should pick `ISV_NETWORK_DIM` (for weight /// tensor sizing) or `ISV_TOTAL_DIM` (for the broadcast bus buffer). diff --git a/crates/ml/src/cuda_pipeline/mod.rs b/crates/ml/src/cuda_pipeline/mod.rs index 4d02933f4..f9dbff8e1 100644 --- a/crates/ml/src/cuda_pipeline/mod.rs +++ b/crates/ml/src/cuda_pipeline/mod.rs @@ -67,6 +67,7 @@ pub mod sp14_isv_slots; pub mod sp15_isv_slots; pub mod sp21_isv_slots; pub mod sp22_isv_slots; +pub mod alpha_isv_slots; pub mod lob_bar; pub use sp4_isv_slots::{ TARGET_Q_BOUND_INDEX, ATOM_POS_BOUND_BASE, WEIGHT_BOUND_BASE, diff --git a/docs/isv-slots.md b/docs/isv-slots.md index e6f306471..1e1db1793 100644 --- a/docs/isv-slots.md +++ b/docs/isv-slots.md @@ -502,3 +502,38 @@ work stream and establishes the slot base for upcoming components: **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). + +## Alpha trading system — durable infrastructure block (2026-05-15) + +Phase E intro commit reserves 12 contiguous slots at `[539..551)` for **system-scoped** infrastructure of the alpha trading stack (stacker / execution-policy diagnostics, controller anchors, population baselines). Unlike the per-iteration SP4..SP22 reservations, this block is named for the *system* — slots are intended to outlive any individual Phase E/F/G milestone. New slots in this range should be added in `alpha_isv_slots.rs` first; spares at 549..550 absorb growth without bumping `ISV_TOTAL_DIM`. + +| Index | Name constant | Role | Producer (initial commit) | Update cadence | Notes | +|-------|-------------------------------------|--------------|----------------------------------------|----------------------|-------| +| 539 | `Q_SPREAD_EMA_INDEX` | Diagnostic | (none; Phase E.1 kill-criteria kernel) | per-rollout-step | `std(Q, axis=action) / |mean(Q)|`; kill-criterion #1 | +| 540 | `ACTION_ENTROPY_EMA_INDEX` | Diagnostic | (none; Phase E.1 kill-criteria kernel) | per-rollout-step | `H(action_dist)` over recent rollouts; kill-criterion #2 | +| 541 | `RETURN_VS_RANDOM_EMA_INDEX` | Diagnostic | (none; Phase E.1 kill-criteria kernel) | per-trade-close | `(rollout_R − random_R) / σ_random`; kill-criterion #3 | +| 542 | `EARLY_Q_MOVEMENT_EMA_INDEX` | Diagnostic | (none; Phase E.1 kill-criteria kernel) | per-epoch | `|Q(s_early) − Q_init|/|Q_init|`; kill-criterion #4 | +| 543 | `STACKER_THRESHOLD_INDEX` | Controller | (none; Phase E.2 stacker controller) | per-rollout-step | Confidence threshold for trade eligibility; engagement-rate self-correction | +| 544 | `TRADE_RATE_TARGET_INDEX` | Anchor | host init at training start | static | Target trade-rate fraction (e.g. 0.08) | +| 545 | `TRADE_RATE_OBSERVED_EMA_INDEX` | Diagnostic | (none; Phase E.2 stacker controller) | per-rollout-step | Observed trade-rate EMA | +| 546 | `STACKER_KELLY_ATTENUATION_INDEX` | Controller | (none; Phase E.2 stacker controller) | per-trade-close | Multiplied with `KELLY_F_SMOOTH_INDEX=280` before contract-cap; bounded [0.1, 1.0] per `pearl_blend_formulas_must_have_permanent_floor` | +| 547 | `RANDOM_BASELINE_MEAN_INDEX` | Anchor | host computes once per fold | per-fold | Mean reward of uniform-random execution policy at the given horizon | +| 548 | `RANDOM_BASELINE_STD_INDEX` | Anchor | host computes once per fold | per-fold | Std of same — used to compute `RETURN_VS_RANDOM_EMA` σ-distance | +| 549 | (reserved spare) | — | — | — | Absorb growth; do not use ad-hoc | +| 550 | (reserved spare) | — | — | — | Absorb growth; do not use ad-hoc | + +**Files touched (intro commit, slot reservation only):** +- `crates/ml/src/cuda_pipeline/alpha_isv_slots.rs` (new) — 10 `pub const *_INDEX` constants + `ALPHA_ISV_BLOCK_LO=539`/`ALPHA_ISV_BLOCK_HI=550` bookends + 4 unit tests (bounds, membership, uniqueness, total-dim coverage) +- `crates/ml/src/cuda_pipeline/mod.rs` — adds `pub mod alpha_isv_slots;` +- `crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs` — `ISV_TOTAL_DIM: 539 → 551`; comment updated to reference `alpha_isv_slots.rs` + +**Producers/consumers status:** intro commit is reservation-only. Producers land later in Phase E: +- Phase E.1: `phase_e_kill_criteria.cu` writes slots 539-542 +- Phase E.2: `stacker_threshold_controller.cu` writes slots 543, 545, 546 (reads 544 as anchor) +- Phase E.0: host writes 544 (trade-rate target) at training start and 547, 548 (baselines) per fold + +State-reset-registry dispatch arms for all 10 active slots land in the immediately-following commit (Phase E Task 2), per `feedback_registry_entries_need_dispatch_arms`. + +**Naming rationale:** SP4..SP22 reservations are *milestone-scoped* (a specific SP iteration); this block is *system-scoped* (alpha trading system across Phase E/F/G/...). The naming difference is intentional — future alpha-system additions go in `alpha_isv_slots.rs`, not in a per-phase file. + +**ISV_TOTAL_DIM:** 539 → 551 (12 slots reserved, 10 active, 2 spare).