feat(sp21): T2.2 Phase 7 — E8 curriculum_concentration → PER alpha boost (atomic)

Wires E8's curriculum_weights distribution into the per_update_pa
alpha boost composition via a new scalar signal:
`compute_curriculum_concentration(weights) = 1 - entropy/log(n)`.
Same pattern as Phases 5+6 (E6 winner_concentration + E7
hindsight_magnitude); all three feed the same boost_delta sum.

Plan revision (mirrors Phase 5+6 pattern):
- Original plan: "wire E8 (curriculum weights) → segment sampling
  weights." Literal interpretation requires new curriculum-segment
  abstraction in PER (segments don't exist — flat ring buffer
  today).
- Resolution: signal-driven from the SHAPE of the weights
  distribution (entropy concentration), not the CONTENT (per-segment
  weighted sampling). Feeds existing per_update_pa kernel; no new
  segment-sampling kernel.
- True per-segment PER sampling deferred to Phase 7.5 (mirrors
  Phase 6.5 deferral for E7's literal injection consumer).

Signal semantics (compute_curriculum_concentration):
- Input: Vec<f32> of E8's per-segment weights (sum=1).
- Output: 1 - entropy/log(n) ∈ [0, 1].
  - 0.0 = uniform (segments equally hard)
  - 1.0 = one segment dominates (concentrated difficulty)
- Single-segment trivially → 1.0
- Cold start (empty input) → 0.0 sentinel
- Zero-weight segments skipped (p log p → 0)

ISV slot allocation:
- CURRICULUM_CONCENTRATION_INDEX = 527
- ISV_TOTAL_DIM 527 → 528 (bus extension)
- Layout fingerprint adds SLOT_527 entry

Kernel change (4 lines, no ABI churn):
- per_update_pa reads isv_signals[527] (already-existing arg from
  Phase 5+6)
- curriculum_term = clamp(curric_conc, 0, 1) × 0.1 ∈ [0, 0.1]
- boost_delta upper bound 0.4 → 0.5 to accommodate new term
- Cold-start short-circuit predicate extended to all 3 signals

Producer wireup:
- enrichment.rs: new helper compute_curriculum_concentration;
  EnrichmentResult.curriculum_concentration field;
  run_enrichments populates it; log line extended
- training_loop.rs: post-enrichment block writes ISV[527]

Files changed:
- crates/ml/src/cuda_pipeline/sp21_isv_slots.rs: +1 slot const
- crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs: ISV_TOTAL_DIM
  bump + fingerprint
- crates/ml-dqn/src/per_kernels.cu: 4-line boost composition
  extension
- crates/ml/src/trainers/dqn/trainer/enrichment.rs: helper + field
- crates/ml/src/trainers/dqn/trainer/training_loop.rs: write ISV
- docs/dqn-wire-up-audit.md: 2026-05-11 audit entry

Verification (passing):
- cargo check -p ml --tests --features cuda: 0 errors
- cargo test -p ml --lib sp21_isv_slots: 3/3
- sp20_aggregate_inputs_test: 12/12
- sp20_phase1_4_wireup_test: 2/2
- sp20_emas_compute_test: 4/4
- sp20_controllers_compute_test: 7/7
- sp21_per_trade_predicted_q_test: 3/3
Total: 34 tests, 0 failures.

After this commit (Phase 8 + 6.5 + 7.5):
- Phase 8: signal-drive remaining controller GAINS in enrichment
- Phase 6.5: true E7 hindsight synthetic injection (deferred)
- Phase 7.5: true E8 per-segment PER sampling (deferred)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-05-10 23:55:46 +02:00
parent a6087a0b23
commit 34d19955ff
6 changed files with 249 additions and 19 deletions

View File

@@ -2622,7 +2622,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 = 527; // SP21 Phase 5+6 adds 2 slots [525..527) for WINNER_CONCENTRATION + HINDSIGHT_MAGNITUDE (PER alpha scaling); Phase 4 added 4 slots [521..525) for BRANCH_LR_SCALE_*; Phase 3 added 1 slot [520..521) for Q_CORRECTION
pub(crate) const ISV_TOTAL_DIM: usize = 528; // SP21 Phase 7 adds 1 slot [527..528) for CURRICULUM_CONCENTRATION (PER alpha scaling, composed with WINNER_CONCENTRATION + HINDSIGHT_MAGNITUDE); Phase 5+6 added 2 slots [525..527); Phase 4 added 4 slots [521..525) for BRANCH_LR_SCALE_*; Phase 3 added 1 slot [520..521) for Q_CORRECTION
/// 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).
@@ -3755,7 +3755,8 @@ const fn layout_fingerprint_seed() -> &'static [u8] {
SLOT_524_BRANCH_LR_SCALE_URGENCY=524;\
SLOT_525_WINNER_CONCENTRATION=525;\
SLOT_526_HINDSIGHT_MAGNITUDE=526;\
ISV_TOTAL_DIM=527;\
SLOT_527_CURRICULUM_CONCENTRATION=527;\
ISV_TOTAL_DIM=528;\
SP19_PRODUCER_HARDCODED_HORIZON_BLEND=sp19_path_b;\
SP14_C_AUX_TRUNK_CONTROL_PLANE=sp14_c_phase_1;\
ALPHA_MACHINERY_DELETED=sp14_c_phase_1;\