diff --git a/crates/ml/src/trainers/dqn/state_reset_registry.rs b/crates/ml/src/trainers/dqn/state_reset_registry.rs index d393e523c..424ae7399 100644 --- a/crates/ml/src/trainers/dqn/state_reset_registry.rs +++ b/crates/ml/src/trainers/dqn/state_reset_registry.rs @@ -534,7 +534,7 @@ impl StateResetRegistry { RegistryEntry { name: "sp4_wiener_state", category: ResetCategory::FoldReset, - description: "GpuDqnTrainer.wiener_state_buf [543 floats total = (71 SP4 + 110 SP5) 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..543) 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` (Task A12; buffer grew 141→207 in Task A13.0, 207→213 in Layer C #260, 213→543 in SP5 Task A1)", + description: "GpuDqnTrainer.wiener_state_buf [(71 + SP5_PRODUCER_COUNT) × 3 floats; post-SP11: (71 + 186) × 3 = 771] = (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 to avoid drift on each subsequent SP.", }, RegistryEntry { name: "sp4_clamp_engage_counters", @@ -971,7 +971,7 @@ impl StateResetRegistry { 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..SP5_WIENER_TOTAL_FLOATS=573)` at fold boundary covers the new D1 triples at offsets [213+(286-174)*3 .. 213+(290-174)*3) = [549..561). The buffer grew from 543 to 561 floats with D1 (SP5_PRODUCER_COUNT linear span 110 → 116; unique-slot count 110 → 114; D2 grew it further to 573 / 120 / 118; see SP5_PRODUCER_COUNT docstring for the linear-span vs unique-slot distinction). reset_for_fold's existing bulk memset of the whole buffer length covers the new triples atomically — no per-slot wiener entry is needed.", + 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 @@ -986,7 +986,7 @@ impl StateResetRegistry { 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..SP5_WIENER_TOTAL_FLOATS=573)` at fold boundary covers the new D2 triples at offsets [213+(290-174)*3 .. 213+(294-174)*3) = [561..573). The buffer grew from 561 to 573 floats with D2 (SP5_PRODUCER_COUNT linear span 116 → 120; unique-slot count 114 → 118; see SP5_PRODUCER_COUNT docstring for the linear-span vs unique-slot distinction). reset_for_fold's existing bulk memset of the whole buffer length covers the new triples atomically — no per-slot wiener entry is needed.", + 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 @@ -1006,7 +1006,7 @@ impl StateResetRegistry { 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..SP5_WIENER_TOTAL_FLOATS=582)` at fold boundary covers the new D3 triples at offsets [213+(294-174)*3 .. 213+(297-174)*3) = [573..582). The buffer grew from 573 to 582 floats with D3 (SP5_PRODUCER_COUNT linear span 120 → 123; unique-slot count 118 → 121; see SP5_PRODUCER_COUNT docstring for the linear-span vs unique-slot distinction). reset_for_fold's existing bulk memset of the whole buffer length covers the new triples atomically — no per-slot wiener entry is needed. 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.", + 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.", }, ]; Self { entries } diff --git a/docs/dqn-wire-up-audit.md b/docs/dqn-wire-up-audit.md index 08b490209..e2e1bc7cc 100644 --- a/docs/dqn-wire-up-audit.md +++ b/docs/dqn-wire-up-audit.md @@ -5044,3 +5044,25 @@ fold-convergence run, the log-space cumulative growth (financials.rs:80-94 documents the 1e-10 clamp ensuring finiteness), but display as fixed-decimal makes the line illegible. Switched to `Return={:+.3e}%`. Cosmetic-only; no training-path impact. + +## SP11 A0 sweep — eliminate stale wiener-buffer refs (2026-05-04) + +The A0 follow-up (`1e5a65912`) fixed two stale references the code- +quality reviewer flagged. The implementer surfaced 3 more locations in +`state_reset_registry.rs` with stale buffer-size literals from prior SPs: + +- `:537 sp4_wiener_state` — `[543 floats total = (71 SP4 + 110 SP5)]` + with growth chain `141→207→213→543` ending at SP5 Task A1 +- `:974 sp5_pnl_aggregation` — `SP5_WIENER_TOTAL_FLOATS=573` (post-D2 stale) +- `:989 sp5_health_composition` — same `=573` stale +- `:1009 sp5_training_metrics_ema` — `SP5_WIENER_TOTAL_FLOATS=582` (post-D3 stale) + +All four converted to formula form `(71 + SP5_PRODUCER_COUNT) × 3` +matching A0 fix-up pattern. Brittle growth chains dropped in favor of +the derivable formula so future SPs don't add another stale literal +each time the buffer grows. Per `feedback_fix_everything_aggressively`: +known-stale refs identified by review get fixed, not deferred. + +Verified: cargo check clean; `state_reset_registry` tests 4/4 pass; no +dispatch-arm or contract-test changes required (formula form is purely +documentation).