From c146c4fffdc2582fb4c5ce7c81053333608ebd7f Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Wed, 6 May 2026 10:49:33 +0200 Subject: [PATCH] =?UTF-8?q?feat(sp15):=20scaffold=20sp15=5Fisv=5Fslots.rs?= =?UTF-8?q?=20with=2046=20slots=20[397..443)=20=E2=80=94=20ISV=5FTOTAL=5FD?= =?UTF-8?q?IM=20396=E2=86=92443?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per spec §4.3 allocation map. Pre-allocates disjoint slot ranges to enable Approach B parallel sub-worktrees without index collisions: - Phase 0.B EGF retune: [397..401) - Phase 1.3 drawdown: [401..407) - Phase 1.2 cost: [407..409) - Phase 1.4 baselines: [409..417) - Phase 3.X-3.5.X teachings + recovery: [417..441) - Phase 3.5 deferred anchors: [441..443) Layout fingerprint extended with all 46 slot names. Pre-SP15 checkpoints will be incompatible (greenfield OK per Q1). Two regression tests verify: (1) every slot < ISV_TOTAL_DIM, (2) layout fingerprint locked at named indices. docs/isv-slots.md gets the SP15 section documenting the allocation map + greenfield sub-worktree plan. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ml/src/cuda_pipeline/gpu_dqn_trainer.rs | 20 ++- crates/ml/src/cuda_pipeline/mod.rs | 1 + crates/ml/src/cuda_pipeline/sp15_isv_slots.rs | 125 ++++++++++++++++++ docs/isv-slots.md | 34 +++++ 4 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 crates/ml/src/cuda_pipeline/sp15_isv_slots.rs diff --git a/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs b/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs index cddf16547..d3aafcfe8 100644 --- a/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs +++ b/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs @@ -1085,7 +1085,7 @@ const ISV_NETWORK_DIM: usize = 23; /// (shifted 112→116 in Plan 4 Task 6 Commit A). /// Written by the constructor; checked at checkpoint load. Fail-fast only — no migration /// path exists. See spec §4.A.2 and `LAYOUT_FINGERPRINT_CURRENT` for structural-hash rationale. -pub(crate) const ISV_TOTAL_DIM: usize = 396; // SP5 + Layer D D1+D2+D3 + SP7 + SP8 + SP9 + SP10 + SP11 + SP13 + SP13 v3 + SP14: 173 + 210 (164 SP5 slots @ 174..278/280..340, with 2-slot gap before cross-fold-persistent Kelly block; Layer D D1 PnL outputs at [286..290); Layer D D2 health composition outputs at [290..294); Layer D D3 training metrics EMA at [294..297); SP7 T1 loss-balance Wiener stats at [297..313); SP7 activation-flag fix per-(head,branch) flags at [313..321); SP8 Fix 36 train_active_frac canary @ [321..322) + LB_MAX_BUDGET per-(head,branch) at [322..330); SP9 Fix 37 Kelly warmup floor at [330..331) + Q_VAR_MAG_EMA at [331..332) + INTENT_EVAL_DIVERGENCE at [332..333) + 3 EMA targets at [333..336) + 3 eval_dist mag bins at [336..339); SP10 Fix 38 EVAL_THOMPSON_TEMP at [339..340); SP11 Fix 39 reward-subsystem controller at [340..367) — 6 component weights [340..346) + 4 controller scalar outputs [346..350) + 2 val-sharpe canaries [350..352) + 6 mag-ratio canaries [352..358) + saboteur engagement [358] + PnL magnitude EMA [359] + popart-component magnitude EMA [360, B1b fix-up] + per-component variance EMAs [361..367, B1b smoke-recovery z-score normalization]; SP13 directional-skill instrumentation at [372..380) — TARGET_DIR_ACC [372] + AUX_DIR_ACC_SHORT/LONG_EMA [373..375) + AUX_DIR_PREDICTION [375] + DIR_SKILL_BONUS_ALPHA/BETA [376..378) + LUCK_WIN_DISCOUNT [378] + SKILL_BONUS_CAP_RATIO [379]; SP13 v3 P0a.T3 Hold-pricing controller at [380..383) — HOLD_COST [380] + HOLD_RATE_TARGET [381] + HOLD_RATE_OBSERVED_EMA [382]; SP14 EGF pearl at [383..396) — Q_DISAGREEMENT_SHORT/LONG_EMA [383..385) + K_AUX/Q_ADAPTIVE [385..387) + BETA_RATE_LIMITER_ADAPTIVE [387] + AUX_DIR_ACC/Q_DISAGREEMENT/ALPHA_GRAD_RAW_VARIANCE_EMA [388..391) + GATE1_OPEN_STATE [391] + ALPHA_GRAD_RAW [392] + ALPHA_GRAD_SMOOTHED [393] + AUX_DIR_ACC_POST_OPEN_MIN [394] + GRADIENT_HACK_LOCKOUT_REMAINING [395]; intentional 5-slot boundary gap at [367..372)) +pub(crate) const ISV_TOTAL_DIM: usize = 443; // SP5 + Layer D D1+D2+D3 + SP7 + SP8 + SP9 + SP10 + SP11 + SP13 + SP13 v3 + SP14: 173 + 210 (164 SP5 slots @ 174..278/280..340, with 2-slot gap before cross-fold-persistent Kelly block; Layer D D1 PnL outputs at [286..290); Layer D D2 health composition outputs at [290..294); Layer D D3 training metrics EMA at [294..297); SP7 T1 loss-balance Wiener stats at [297..313); SP7 activation-flag fix per-(head,branch) flags at [313..321); SP8 Fix 36 train_active_frac canary @ [321..322) + LB_MAX_BUDGET per-(head,branch) at [322..330); SP9 Fix 37 Kelly warmup floor at [330..331) + Q_VAR_MAG_EMA at [331..332) + INTENT_EVAL_DIVERGENCE at [332..333) + 3 EMA targets at [333..336) + 3 eval_dist mag bins at [336..339); SP10 Fix 38 EVAL_THOMPSON_TEMP at [339..340); SP11 Fix 39 reward-subsystem controller at [340..367) — 6 component weights [340..346) + 4 controller scalar outputs [346..350) + 2 val-sharpe canaries [350..352) + 6 mag-ratio canaries [352..358) + saboteur engagement [358] + PnL magnitude EMA [359] + popart-component magnitude EMA [360, B1b fix-up] + per-component variance EMAs [361..367, B1b smoke-recovery z-score normalization]; SP13 directional-skill instrumentation at [372..380) — TARGET_DIR_ACC [372] + AUX_DIR_ACC_SHORT/LONG_EMA [373..375) + AUX_DIR_PREDICTION [375] + DIR_SKILL_BONUS_ALPHA/BETA [376..378) + LUCK_WIN_DISCOUNT [378] + SKILL_BONUS_CAP_RATIO [379]; SP13 v3 P0a.T3 Hold-pricing controller at [380..383) — HOLD_COST [380] + HOLD_RATE_TARGET [381] + HOLD_RATE_OBSERVED_EMA [382]; SP14 EGF pearl at [383..396) — Q_DISAGREEMENT_SHORT/LONG_EMA [383..385) + K_AUX/Q_ADAPTIVE [385..387) + BETA_RATE_LIMITER_ADAPTIVE [387] + AUX_DIR_ACC/Q_DISAGREEMENT/ALPHA_GRAD_RAW_VARIANCE_EMA [388..391) + GATE1_OPEN_STATE [391] + ALPHA_GRAD_RAW [392] + ALPHA_GRAD_SMOOTHED [393] + AUX_DIR_ACC_POST_OPEN_MIN [394] + GRADIENT_HACK_LOCKOUT_REMAINING [395]; intentional 5-slot boundary gap at [367..372)) /// 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). @@ -2143,7 +2143,23 @@ const fn layout_fingerprint_seed() -> &'static [u8] { ALPHA_GRAD_RAW_VARIANCE_EMA=390;GATE1_OPEN_STATE=391;\ ALPHA_GRAD_RAW=392;ALPHA_GRAD_SMOOTHED=393;\ AUX_DIR_ACC_POST_OPEN_MIN=394;GRADIENT_HACK_LOCKOUT_REMAINING=395;\ - ISV_TOTAL_DIM=396;\ + EGF_SCHMITT_HI=397;EGF_SCHMITT_LO=398;EGF_VAR_AUX_REF=399;EGF_VAR_Q_REF=400;\ + DD_CURRENT=401;DD_MAX=402;DD_RECOVERY_BARS=403;DD_PERSISTENCE=404;CALMAR=405;DD_PCT=406;\ + OFI_IMPACT_LAMBDA=407;COST_PER_BAR_AVG=408;\ + BASELINE_BUYHOLD_SHARPE=409;BASELINE_HOLD_ONLY_SHARPE=410;\ + BASELINE_RANDOM_DIR_KELLY_SHARPE=411;BASELINE_NAIVE_MOMENTUM_SHARPE=412;\ + BASELINE_AUX_ONLY_SHARPE=413;BASELINE_MAG_QUARTER_FIXED_SHARPE=414;\ + BASELINE_TRAIL_ONLY_SHARPE=415;BASELINE_NAIVE_REVERSION_SHARPE=416;\ + ALPHA_SPLIT=417;GRAD_NORM_QUALITY=418;GRAD_NORM_DISCIPLINE=419;\ + LAMBDA_DD=420;DD_THRESHOLD=421;DD_PENALTY_GRAD_NORM=422;\ + REGRET_EMA=423;LAMBDA_REGRET=424;REGRET_GRAD_NORM=425;\ + HOLD_FLOOR_ALPHA=426;HOLD_FLOOR_K=427;HOLD_FLOOR_EPS0=428;ENTROPY_DIST_REF=429;\ + DD_ASYMMETRY_LAMBDA=430;R_GAIN_DD_BOOST=431;DD_DIST_VAR=432;\ + COOLDOWN_K_THRESHOLD=433;COOLDOWN_M_BARS=434;COOLDOWN_BARS_REMAINING=435;\ + PLASTICITY_FIRED_THIS_FOLD=436;PLASTICITY_PERSISTENCE_THRESHOLD=437;PLASTICITY_WARM_BARS_REMAINING=438;\ + DD_TRAJECTORY_DECREASING=439;RECOVERY_OVERSAMPLE_WEIGHT=440;\ + DD_TRAJECTORY_FLOOR=441;MEDIAN_STREAK_LENGTH=442;\ + ISV_TOTAL_DIM=443;\ PARAM_W_A_H_S1=0;PARAM_B_A_H_S1=1;PARAM_W_B_H_S1=2;PARAM_B_B_H_S1=3;\ PARAM_W_RESIDUAL_H_S1=4;PARAM_GAMMA_H_S1=5;PARAM_BETA_H_S1=6;\ PARAM_W_A_H_S2=7;PARAM_B_A_H_S2=8;PARAM_W_B_H_S2=9;PARAM_B_B_H_S2=10;\ diff --git a/crates/ml/src/cuda_pipeline/mod.rs b/crates/ml/src/cuda_pipeline/mod.rs index 0c7777669..e8d126004 100644 --- a/crates/ml/src/cuda_pipeline/mod.rs +++ b/crates/ml/src/cuda_pipeline/mod.rs @@ -63,6 +63,7 @@ pub mod sp5_isv_slots; pub mod sp11_isv_slots; pub mod sp13_isv_slots; pub mod sp14_isv_slots; +pub mod sp15_isv_slots; pub use sp4_isv_slots::{ TARGET_Q_BOUND_INDEX, ATOM_POS_BOUND_BASE, WEIGHT_BOUND_BASE, ADAM_M_BOUND_BASE, ADAM_V_BOUND_BASE, WD_RATE_BASE, diff --git a/crates/ml/src/cuda_pipeline/sp15_isv_slots.rs b/crates/ml/src/cuda_pipeline/sp15_isv_slots.rs new file mode 100644 index 000000000..68a72957e --- /dev/null +++ b/crates/ml/src/cuda_pipeline/sp15_isv_slots.rs @@ -0,0 +1,125 @@ +// crates/ml/src/cuda_pipeline/sp15_isv_slots.rs +//! SP15 ISV slot constants — slot allocation map per spec §4.3. +//! +//! Pre-allocates disjoint slot ranges per phase to enable Approach B +//! parallel-dispatch sub-worktrees without index collisions. SP14 occupied +//! slots 383-395 (`ISV_TOTAL_DIM = 396` post-merge `0275a25d9`). SP15 +//! starts at 397 and ends at 443 (46 slots total). + +// === Phase 0.B: SP14 EGF retune anchors (4 slots) === +pub const EGF_SCHMITT_HI_INDEX: usize = 397; +pub const EGF_SCHMITT_LO_INDEX: usize = 398; +pub const EGF_VAR_AUX_REF_INDEX: usize = 399; +pub const EGF_VAR_Q_REF_INDEX: usize = 400; + +// === Phase 1.3: drawdown reporting (6 slots) === +pub const DD_CURRENT_INDEX: usize = 401; +pub const DD_MAX_INDEX: usize = 402; +pub const DD_RECOVERY_BARS_INDEX: usize = 403; +pub const DD_PERSISTENCE_INDEX: usize = 404; +pub const CALMAR_INDEX: usize = 405; +pub const DD_PCT_INDEX: usize = 406; + +// === Phase 1.2: cost kernel (2 slots) === +pub const OFI_IMPACT_LAMBDA_INDEX: usize = 407; +pub const COST_PER_BAR_AVG_INDEX: usize = 408; + +// === Phase 1.4: 8 counterfactual baselines (8 slots) === +pub const BASELINE_BUYHOLD_SHARPE_INDEX: usize = 409; +pub const BASELINE_HOLD_ONLY_SHARPE_INDEX: usize = 410; +pub const BASELINE_RANDOM_DIR_KELLY_SHARPE_INDEX: usize = 411; +pub const BASELINE_NAIVE_MOMENTUM_SHARPE_INDEX: usize = 412; +pub const BASELINE_AUX_ONLY_SHARPE_INDEX: usize = 413; +pub const BASELINE_MAG_QUARTER_FIXED_SHARPE_INDEX: usize = 414; +pub const BASELINE_TRAIL_ONLY_SHARPE_INDEX: usize = 415; +pub const BASELINE_NAIVE_REVERSION_SHARPE_INDEX: usize = 416; + +// === Phase 3.1: r_quality + r_discipline split (3 slots) === +pub const ALPHA_SPLIT_INDEX: usize = 417; +pub const GRAD_NORM_QUALITY_INDEX: usize = 418; +pub const GRAD_NORM_DISCIPLINE_INDEX: usize = 419; + +// === Phase 3.3: quadratic DD penalty (3 slots) === +pub const LAMBDA_DD_INDEX: usize = 420; +pub const DD_THRESHOLD_INDEX: usize = 421; +pub const DD_PENALTY_GRAD_NORM_INDEX: usize = 422; + +// === Phase 3.4: regret signal (3 slots) === +pub const REGRET_EMA_INDEX: usize = 423; +pub const LAMBDA_REGRET_INDEX: usize = 424; +pub const REGRET_GRAD_NORM_INDEX: usize = 425; + +// === Phase 3.5: confidence-aware Hold floor (4 slots) === +pub const HOLD_FLOOR_ALPHA_INDEX: usize = 426; +pub const HOLD_FLOOR_K_INDEX: usize = 427; +pub const HOLD_FLOOR_EPS0_INDEX: usize = 428; +pub const ENTROPY_DIST_REF_INDEX: usize = 429; + +// === Phase 3.5.2: DD asymmetric reward (3 slots) === +pub const DD_ASYMMETRY_LAMBDA_INDEX: usize = 430; +pub const R_GAIN_DD_BOOST_INDEX: usize = 431; +pub const DD_DIST_VAR_INDEX: usize = 432; + +// === Phase 3.5.3: cooldown gate (3 slots) === +pub const COOLDOWN_K_THRESHOLD_INDEX: usize = 433; +pub const COOLDOWN_M_BARS_INDEX: usize = 434; +pub const COOLDOWN_BARS_REMAINING_INDEX: usize = 435; + +// === Phase 3.5.4: plasticity injection (3 slots) === +pub const PLASTICITY_FIRED_THIS_FOLD_INDEX: usize = 436; +pub const PLASTICITY_PERSISTENCE_THRESHOLD_INDEX: usize = 437; +pub const PLASTICITY_WARM_BARS_REMAINING_INDEX: usize = 438; + +// === Phase 3.5.5: recovery curriculum in PER (2 slots) === +pub const DD_TRAJECTORY_DECREASING_INDEX: usize = 439; +pub const RECOVERY_OVERSAMPLE_WEIGHT_INDEX: usize = 440; + +// === Phase 3.5 deferred ISV anchors (2 slots) === +pub const DD_TRAJECTORY_FLOOR_INDEX: usize = 441; +pub const MEDIAN_STREAK_LENGTH_INDEX: usize = 442; + +pub const SP15_SLOT_BASE: usize = 397; +pub const SP15_SLOT_END: usize = 443; +pub const SP15_SLOT_COUNT: usize = SP15_SLOT_END - SP15_SLOT_BASE; + +#[cfg(test)] +mod tests { + use super::*; + use crate::cuda_pipeline::gpu_dqn_trainer::ISV_TOTAL_DIM; + + /// Regression test: every SP15 slot fits within ISV_TOTAL_DIM. + /// Paired contract with the ISV_TOTAL_DIM bump in gpu_dqn_trainer.rs. + #[test] + fn all_sp15_slots_fit_within_isv_total_dim() { + assert!(MEDIAN_STREAK_LENGTH_INDEX < ISV_TOTAL_DIM, + "MEDIAN_STREAK_LENGTH_INDEX={} >= ISV_TOTAL_DIM={}; bump ISV_TOTAL_DIM", + MEDIAN_STREAK_LENGTH_INDEX, ISV_TOTAL_DIM); + assert_eq!(SP15_SLOT_END, MEDIAN_STREAK_LENGTH_INDEX + 1); + assert_eq!(SP15_SLOT_COUNT, 46); + } + + /// Layout fingerprint regression: each named slot at its allocated index. + #[test] + fn sp15_slot_layout_locked() { + assert_eq!(EGF_SCHMITT_HI_INDEX, 397); + assert_eq!(EGF_SCHMITT_LO_INDEX, 398); + assert_eq!(EGF_VAR_AUX_REF_INDEX, 399); + assert_eq!(EGF_VAR_Q_REF_INDEX, 400); + assert_eq!(DD_CURRENT_INDEX, 401); + assert_eq!(DD_PCT_INDEX, 406); + assert_eq!(OFI_IMPACT_LAMBDA_INDEX, 407); + assert_eq!(BASELINE_BUYHOLD_SHARPE_INDEX, 409); + assert_eq!(BASELINE_NAIVE_REVERSION_SHARPE_INDEX, 416); + assert_eq!(ALPHA_SPLIT_INDEX, 417); + assert_eq!(LAMBDA_DD_INDEX, 420); + assert_eq!(REGRET_EMA_INDEX, 423); + assert_eq!(HOLD_FLOOR_ALPHA_INDEX, 426); + assert_eq!(DD_ASYMMETRY_LAMBDA_INDEX, 430); + assert_eq!(COOLDOWN_K_THRESHOLD_INDEX, 433); + assert_eq!(PLASTICITY_FIRED_THIS_FOLD_INDEX, 436); + assert_eq!(PLASTICITY_WARM_BARS_REMAINING_INDEX, 438); + assert_eq!(DD_TRAJECTORY_DECREASING_INDEX, 439); + assert_eq!(DD_TRAJECTORY_FLOOR_INDEX, 441); + assert_eq!(MEDIAN_STREAK_LENGTH_INDEX, 442); + } +} diff --git a/docs/isv-slots.md b/docs/isv-slots.md index 2bc6f0a9c..f651df1dd 100644 --- a/docs/isv-slots.md +++ b/docs/isv-slots.md @@ -426,3 +426,37 @@ values are omitted from the emit (recomputing host-side would violate - `let warmup_gate: f32 = 1.0;` and `.arg(&warmup_gate)` from B.4 oracle tests **Net result:** EGF gate's warmup behavior now lives entirely in the variance-driven k_aux/k_q sigmoid steepness controller. ISV-signal-driven via slots 388 (var_aux) and 389 (var_q). No hardcoded step counter. Honors `feedback_isv_for_adaptive_bounds`. + +## SP15 — Trader Discipline Recovery (Pre-Phase P.2 reservation, 2026-05-06) + +SP15 Pre-Phase Task P.2 extends `ISV_TOTAL_DIM` from 396 → 443 by reserving 46 +contiguous slots at `[397..443)`. The allocation pre-claims disjoint ranges +across 3 sub-worktrees (Approach B parallel-dispatch) so Phase 0/1/2A can +land producers and consumers independently without index collisions. + +**Allocation map (per spec §4.3):** + +| Range | Phase | Purpose | +|-------|-------|---------| +| `[397..401)` | Phase 0.B | EGF retune anchors (SCHMITT_HI/LO + VAR_AUX/Q_REF) | +| `[401..407)` | Phase 1.3 | Drawdown reporting (current/max/recovery_bars/persistence/calmar/dd_pct) | +| `[407..409)` | Phase 1.2 | Cost kernel (OFI_IMPACT_LAMBDA + COST_PER_BAR_AVG) | +| `[409..417)` | Phase 1.4 | 8 counterfactual baselines (buyhold/hold-only/random-dir-kelly/naive-momentum/aux-only/mag-quarter-fixed/trail-only/naive-reversion sharpe) | +| `[417..420)` | Phase 3.1 | r_quality + r_discipline split (ALPHA_SPLIT + grad-norm quality/discipline) | +| `[420..423)` | Phase 3.3 | Quadratic DD penalty (LAMBDA_DD + DD_THRESHOLD + DD_PENALTY_GRAD_NORM) | +| `[423..426)` | Phase 3.4 | Regret signal (REGRET_EMA + LAMBDA_REGRET + REGRET_GRAD_NORM) | +| `[426..430)` | Phase 3.5 | Confidence-aware Hold floor (HOLD_FLOOR_ALPHA/K/EPS0 + ENTROPY_DIST_REF) | +| `[430..433)` | Phase 3.5.2 | DD asymmetric reward (DD_ASYMMETRY_LAMBDA + R_GAIN_DD_BOOST + DD_DIST_VAR) | +| `[433..436)` | Phase 3.5.3 | Cooldown gate (K_THRESHOLD + M_BARS + BARS_REMAINING) | +| `[436..439)` | Phase 3.5.4 | Plasticity injection (FIRED_THIS_FOLD + PERSISTENCE_THRESHOLD + WARM_BARS_REMAINING) | +| `[439..441)` | Phase 3.5.5 | Recovery curriculum in PER (DD_TRAJECTORY_DECREASING + RECOVERY_OVERSAMPLE_WEIGHT) | +| `[441..443)` | Phase 3.5 deferred | DD_TRAJECTORY_FLOOR + MEDIAN_STREAK_LENGTH ISV anchors | + +**Files touched (P.2 atomic):** +- `crates/ml/src/cuda_pipeline/sp15_isv_slots.rs` (new) — 46 `pub const *_INDEX` constants + SP15_SLOT_BASE/END/COUNT + 2 regression tests (`all_sp15_slots_fit_within_isv_total_dim`, `sp15_slot_layout_locked`) +- `crates/ml/src/cuda_pipeline/mod.rs` — `pub mod sp15_isv_slots;` declaration +- `crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs` — `ISV_TOTAL_DIM: 396 → 443`, `layout_fingerprint_seed()` extended with all 46 slot `name=index` entries before the `ISV_TOTAL_DIM=443` marker (forces fingerprint hash bump → pre-SP15 checkpoints invalidated, greenfield OK per spec Q1) + +**Greenfield sub-worktrees:** `.worktrees/sp15-phase0-egf-retune`, `.worktrees/sp15-phase1-honest-numbers`, `.worktrees/sp15-phase2a-test-scaffold` rebase onto this commit so each phase's producers/consumers see the slot map. + +**Producers/consumers status:** P.2 lands the slot reservation only; all 46 slots are zero-initialized until per-phase tasks land producers (Phase 0/1/3) and atomic consumer migration (Phase 3.X). Mirrors the SP4/SP5/SP11 pre-allocation pattern.