fix(class-a-p1-wiring): var_floor q_gap-only adaptive (1 of 4 wireable)
Per Class A audit P1 wiring batch — only 1 of 4 items was wireable as spec'd. The other 3 are deferred per the spec's "DEFER not BLOCK" rule because their target ISV slots either don't exist or are unit-incompatible with the consumer site. Items: 1. trade_physics.cuh:548 (DD floor_dd 0.25f) — DEFERRED. Slot 421 (DD_THRESHOLD_INDEX) holds the DD trigger threshold (~0.05), NOT the penalty saturation floor (~0.25). Different parameters; substituting would break the ramp formula `(dd-thr)/(floor-thr)`. Needs a new slot for the saturation floor. 2. gpu_experience_collector.rs:343-344 (dd_threshold + w_dd config) — DEFERRED. No W_DD slot exists in any sp*_isv_slots.rs. The legacy compute_drawdown_penalty path (experience_kernels.cu:3769) uses config scalars; the SP15 reward axis (compute_sp15_final_reward_kernel) already reads slot 421 directly. Wiring needs a new W_DD slot. 3. plan_threshold_update_kernel.cu:44 (plan threshold floor) — DEFERRED. Unit mismatch: ema and plan_threshold are probabilities ∈[0,1]; Q_DIR_ABS_REF (slot 21) is a Q-value magnitude EMA (5–50). Scaling a probability by a Q-magnitude is dimensionally meaningless. 4. experience_kernels.cu:2471 (var_floor formula) — DONE. Drop the hardcoded 0.25f lower bound. Was `fminf(fmaxf(q_gap*0.5f, 0.25f), 1.0f)`; now `fminf(q_gap*0.5f, 1.0f)`. NULL-q_gaps fallback uses ε=1e-6f for numerical safety (vs prior 0.25f). var_scale itself remains (0,1] from `1/(1+sqrt(var_q))` so the multiplicative chain stays bounded. Cumulative WR-plateau fix series: - Class C bug 1 + P0-B (8f218cab2) - P0-C (316db416b) - P0-A (394de7d43) - P1 wiring (this commit, partial — Items 1/2/3 deferred to producer batch) Per feedback_isv_for_adaptive_bounds.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2467,10 +2467,16 @@ extern "C" __global__ void experience_env_step(
|
||||
/* Use max variance across the two exposure branches (direction + magnitude) */
|
||||
float var_q = fmaxf(var_taken, var_mag);
|
||||
float var_scale = 1.0f / (1.0f + sqrtf(var_q));
|
||||
/* Permanent floor — same q_gap-derived conviction clamped at line 1628. */
|
||||
/* Permanent floor — q_gap-derived conviction (no hardcoded 0.25f).
|
||||
* Class A P1 wiring (2026-05-08): per `feedback_isv_for_adaptive_bounds.md`,
|
||||
* the floor is now entirely q_gap-driven — the prior 0.25f lower bound
|
||||
* was a structural floor that signal-driven controllers couldn't
|
||||
* escape. When q_gaps is NULL the var_floor mechanism short-circuits
|
||||
* to a tiny ε (1e-6f) for numerical safety; var_scale itself remains
|
||||
* (0,1] from `1/(1+sqrt(var_q))`. */
|
||||
float var_floor = (q_gaps != NULL)
|
||||
? fminf(fmaxf(q_gaps[i] * 0.5f, 0.25f), 1.0f)
|
||||
: 0.25f;
|
||||
? fminf(q_gaps[i] * 0.5f, 1.0f)
|
||||
: 1e-6f;
|
||||
var_scale = fmaxf(var_scale, var_floor);
|
||||
/* Task 0.3: persist the per-sample Kelly scale for host-side epoch-mean
|
||||
* reduction. Host filters on `> 0.0f` to distinguish measured samples
|
||||
|
||||
@@ -7910,3 +7910,35 @@ No additional consumers found via `grep -rnE "REWARD_POS_CAP|REWARD_NEG_CAP" cra
|
||||
- Class A P0-B (`8f218cab2`): Kelly warmup floor wiring — keeps Kelly cap from going to 0 cold-start.
|
||||
- Class A P0-C (`316db416b`): MIN_HOLD_TARGET adaptive from AVG_WIN_HOLD_TIME — patience-matched holds.
|
||||
- Class A P0-A (this commit): REWARD_POS/NEG_CAP adaptive from realized return distribution — restores upper-tail alpha to the controller's view.
|
||||
|
||||
## Class A P1 wiring batch: 4 hardcoded → ISV (2026-05-08)
|
||||
|
||||
Class A P1 audit identified four hardcoded constants that the Class A audit flagged as creating "structural floors/ceilings" the surrounding ISV-driven controllers couldn't escape. All four were intended as wiring-only fixes (existing ISV producers), but on inspection three of the four require slot allocations or have unit-mismatch issues — only Item 4 was wireable. Per the spec's "DEFER not BLOCK" rule, Items 1-3 are deferred to a producer batch and Item 4 lands here.
|
||||
|
||||
### Items
|
||||
|
||||
#### Item 1 — DEFERRED: trade_physics.cuh:548 `floor_dd = 0.25f`
|
||||
- **Site**: `crates/ml/src/cuda_pipeline/trade_physics.cuh:548` in `compute_drawdown_penalty`.
|
||||
- **Audit's intent**: replace the hardcoded `floor_dd = 0.25f` (DD-penalty saturation point, where penalty reaches `-5*w_dd`) with `isv[SP15_DD_THRESHOLD_INDEX=421]`.
|
||||
- **Why deferred**: slot 421 holds the DD **trigger threshold** (~0.05 — the lower bound where the penalty starts), not the DD **saturation floor** (~0.25 — the upper bound where the penalty saturates). The two parameters have different semantics and must satisfy `floor_dd > dd_threshold` (otherwise the formula `(dd - dd_threshold) / (floor_dd - dd_threshold)` divides by ≤ 0). Reading slot 421 for `floor_dd` would make `floor_dd ≈ dd_threshold`, breaking the ramp. There is no existing ISV producer for the saturation floor — needs new slot allocation in a follow-up producer batch.
|
||||
|
||||
#### Item 2 — DEFERRED: gpu_experience_collector.rs:343-344 `dd_threshold=0.02 + w_dd=1.0`
|
||||
- **Site**: `crates/ml/src/cuda_pipeline/gpu_experience_collector.rs:343-344` in `ExperienceCollectorConfig::default`.
|
||||
- **Audit's intent**: read `dd_threshold` and `w_dd` from ISV slots.
|
||||
- **Why deferred**: per the spec's "STOP this item if slots don't exist" rule. `grep -nE "W_DD|w_dd" crates/ml/src/cuda_pipeline/sp*_isv_slots.rs` returns no W_DD slot. SP15 slot 421 (`DD_THRESHOLD_INDEX`) exists for the threshold but its value flows through the SP15 reward axis path (`compute_sp15_final_reward_kernel`), not through the legacy `compute_drawdown_penalty` → `experience_kernels.cu:3769` path. Wiring would require either a new slot for `w_dd` or a contract migration to retire the legacy DD-penalty path entirely. Defer to producer batch.
|
||||
|
||||
#### Item 3 — DEFERRED: plan_threshold_update_kernel.cu:44 unit mismatch
|
||||
- **Site**: `crates/ml/src/cuda_pipeline/plan_threshold_update_kernel.cu:44`.
|
||||
- **Audit's intent**: scale the `fmaxf(0.1f, 0.5f * ema)` floor/multiplier by `isv[Q_DIR_ABS_REF_INDEX=21]`.
|
||||
- **Why deferred**: unit mismatch. `ema` (and `plan_threshold` itself) is a **probability ∈ [0,1]** (running mean of per-sample readiness ∈ [0,1]). `Q_DIR_ABS_REF` is a **Q-value magnitude EMA** (typically 5–50). Multiplying a probability by a Q-magnitude produces a dimensionally meaningless quantity that would break the consumer site's `> threshold` comparisons (consumers compare against `readiness ∈ [0,1]`). The 0.1 / 0.5 hardcoded constants here are dimensionless probability fractions, not signal-bound coefficients — they are correctly literal and should not be scaled. Slot 21 is wrong for this site; the proper fix is either (a) leave as-is (the constants are unit-correct), or (b) introduce a probability-unit ISV scalar in a follow-up.
|
||||
|
||||
#### Item 4 — DONE: experience_kernels.cu:2471 `var_floor` hardcoded 0.25f lower bound
|
||||
- **Site**: `crates/ml/src/cuda_pipeline/experience_kernels.cu:2471`.
|
||||
- **Change**: drop the hardcoded `0.25f` lower bound from the `var_floor` formula. Was `fminf(fmaxf(q_gaps[i] * 0.5f, 0.25f), 1.0f)`; now `fminf(q_gaps[i] * 0.5f, 1.0f)`. When `q_gaps == NULL`, the var_floor mechanism short-circuits to a tiny ε (1e-6f) for numerical safety — var_scale remains (0, 1] from `1/(1+sqrt(var_q))` so the multiplicative chain doesn't go to zero.
|
||||
- **Rationale**: per audit, the 0.25f floor was a structural anchor that prevented `var_floor` from being entirely signal-driven. Per `feedback_isv_for_adaptive_bounds.md`, the floor must come from an ISV signal — `q_gaps` (already a per-sample conviction signal upstream) is the right driver, and the 0.25f baseline silenced its low-conviction portion of the range.
|
||||
- **Verification**: cargo check + sp14_oracle_tests + sp15_phase1_oracle_tests pass.
|
||||
|
||||
### Concerns surfaced
|
||||
|
||||
1. The audit description for Item 1 conflates `floor_dd` (saturation point) and `dd_threshold` (trigger point) — these are distinct parameters in `compute_drawdown_penalty`. Future producer batch must add a separate slot for the saturation floor, not reuse slot 421.
|
||||
2. The legacy `compute_drawdown_penalty` (called from `experience_kernels.cu:3769`) and the SP15 `sp15_dd_penalty` (called from `compute_sp15_final_reward_kernel.cu:154`) coexist with separate parameter flows. The SP15 path is fully ISV-driven (slots 420, 421); the legacy path takes config scalars. A future cleanup should retire the legacy path or migrate it to ISV.
|
||||
|
||||
Reference in New Issue
Block a user