plan(sp17): allocate ISV slots [474..483) for dueling-Q diagnostics

9 slots: A_var_ema × 4 branches (per-branch advantage variance EMA)
+ V_share × 4 branches (V/(V+A) magnitude share) + adaptive
advantage_clip_bound. All Pearl-A first-observation bootstrap with
fold-reset registry entries + dispatch arms in
trainer/training_loop.rs::reset_named_state. Bump ISV_TOTAL_DIM 474 →
483 + layout fingerprint seed.

Per `feedback_isv_for_adaptive_bounds`: advantage_clip_bound is
producer-tracked from p99(|A_centered|) × 1.5 safety factor, never
hardcoded. Bounds [0.1, 100.0] are Category-1 dimensional safety floors.

No consumer change in this commit (additive infrastructure). Phase 1
mean-centering producer (atomic across compute_expected_q +
c51_loss + c51_grad + mag_concat_qdir) lands in the next 4 commits.

Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-05-08 20:35:29 +02:00
parent 25ff1d4195
commit a225926e5f
5 changed files with 277 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -633,6 +633,53 @@ pub const WELFORD_EPS: f32 = 1.0e-6;
pub const SP16_T3_WIENER_SLOT_BASE: usize = 462;
pub const SP16_T3_WIENER_SLOT_END: usize = 474;
// ── SP17 (2026-05-08): dueling Q-network identifiability diagnostics ───
// Adds 9 ISV slots driving the V/A diagnostic chain that observes
// whether the post-SP17 mean-centered advantage is doing real work and
// detects regression to the pre-SP17 V-dominated regime. Per
// `feedback_isv_for_adaptive_bounds`, all signal-driven; the
// `advantage_clip_bound` is producer-tracked from p99(|A_centered|),
// never hardcoded.
//
// Mathematical rationale: with mean-zero identifiability
// `A_centered[a, z] = A[a, z] (1/|branch|) Σ_a A[a, z]`, the per-branch
// variance of `A_centered` over actions measures how much the policy
// discriminates between actions. Var(A) → 0 = "all actions equivalent,
// V dominates" = pre-SP17 pathology re-emerging. Var(A) > 0 with V_share
// stable around 0.5 = healthy dueling decomposition.
//
// Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md
pub const A_VAR_EMA_DIR_INDEX: usize = 474; // Var(A_centered) over dir actions, EMA
pub const A_VAR_EMA_MAG_INDEX: usize = 475;
pub const A_VAR_EMA_ORD_INDEX: usize = 476;
pub const A_VAR_EMA_URG_INDEX: usize = 477;
pub const V_SHARE_DIR_INDEX: usize = 478; // |V_contribution| / (|V| + |A_centered|)
pub const V_SHARE_MAG_INDEX: usize = 479;
pub const V_SHARE_ORD_INDEX: usize = 480;
pub const V_SHARE_URG_INDEX: usize = 481;
pub const ADVANTAGE_CLIP_BOUND_INDEX: usize = 482; // adaptive |A_centered| upper bound
// Sentinels — Pearl-A first-observation bootstrap.
pub const SENTINEL_A_VAR_EMA: f32 = 0.0;
pub const SENTINEL_V_SHARE: f32 = 0.5; // healthy 50/50 split as cold-start
pub const SENTINEL_ADVANTAGE_CLIP_BOUND: f32 = 1.0; // 1.0 → no effective clipping pre-first-obs
// Category-1 dimensional safety bounds per `feedback_isv_for_adaptive_bounds`.
// Floor 0.1: below this any centered advantage is essentially noise; clip
// would erase the action signal. Ceiling 100.0: above this a single
// adversarial outlier can dominate per-batch EMAs.
pub const ADVANTAGE_CLIP_BOUND_MIN: f32 = 0.1;
pub const ADVANTAGE_CLIP_BOUND_MAX: f32 = 100.0;
// Producer constants. Safety factor 1.5× p99 mirrors the SP14 P0-A
// REWARD_POS_CAP producer pattern. EMA α slow per-fold cadence (the bound
// shouldn't track per-batch noise).
pub const ADVANTAGE_CLIP_SAFETY_FACTOR: f32 = 1.5;
pub const ADVANTAGE_CLIP_EMA_ALPHA: f32 = 0.01;
pub const SP17_DUELING_SLOT_BASE: usize = 474;
pub const SP17_DUELING_SLOT_END: usize = 483;
#[cfg(test)]
mod tests {
use super::*;
@@ -971,4 +1018,40 @@ mod tests {
SP16_T3_WIENER_SLOT_END, ISV_TOTAL_DIM,
);
}
/// Lock SP17 (2026-05-08) dueling-Q identifiability diagnostic slot layout.
/// 9 contiguous slots [474..483) — A_var_ema per branch (4) + V_share
/// per branch (4) + adaptive advantage_clip_bound (1).
#[test]
fn sp17_dueling_slot_layout_locked() {
assert_eq!(SP17_DUELING_SLOT_BASE, 474);
assert_eq!(SP17_DUELING_SLOT_END, 483);
assert_eq!(A_VAR_EMA_DIR_INDEX, 474);
assert_eq!(A_VAR_EMA_MAG_INDEX, 475);
assert_eq!(A_VAR_EMA_ORD_INDEX, 476);
assert_eq!(A_VAR_EMA_URG_INDEX, 477);
assert_eq!(V_SHARE_DIR_INDEX, 478);
assert_eq!(V_SHARE_MAG_INDEX, 479);
assert_eq!(V_SHARE_ORD_INDEX, 480);
assert_eq!(V_SHARE_URG_INDEX, 481);
assert_eq!(ADVANTAGE_CLIP_BOUND_INDEX, 482);
// Pearl-A bootstrap sentinels.
assert_eq!(SENTINEL_A_VAR_EMA, 0.0);
assert_eq!(SENTINEL_V_SHARE, 0.5); // initial 50/50 split
assert_eq!(SENTINEL_ADVANTAGE_CLIP_BOUND, 1.0); // 1.0 = "no effective clipping" cold-start
// Category-1 dimensional safety bounds per `feedback_isv_for_adaptive_bounds`.
assert_eq!(ADVANTAGE_CLIP_BOUND_MIN, 0.1);
assert_eq!(ADVANTAGE_CLIP_BOUND_MAX, 100.0);
}
#[test]
fn all_sp17_slots_fit_within_isv_total_dim() {
use crate::cuda_pipeline::gpu_dqn_trainer::ISV_TOTAL_DIM;
assert!(
SP17_DUELING_SLOT_END <= ISV_TOTAL_DIM,
"SP17_DUELING_SLOT_END={} exceeds ISV_TOTAL_DIM={}; \
bump ISV_TOTAL_DIM in gpu_dqn_trainer.rs (and update layout_fingerprint_seed()).",
SP17_DUELING_SLOT_END, ISV_TOTAL_DIM,
);
}
}

View File

@@ -1836,6 +1836,62 @@ impl StateResetRegistry {
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..(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.",
},
// ── SP17 (2026-05-08): dueling-Q identifiability diagnostics ──────
// Nine slots [474..483) driving the V/A diagnostic chain that
// observes whether the post-SP17 mean-centered advantage is
// doing real work and detects regression to the pre-SP17
// V-dominated regime. Producer + consumer kernels land in the
// 4-commit Phase 1-3 atomic migration (compute_expected_q +
// c51_loss + c51_grad + mag_concat_qdir mean-centering) per
// `feedback_no_partial_refactor`; this commit is additive
// infrastructure only. All Pearl-A first-observation
// bootstraps. Plan:
// docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.
RegistryEntry {
name: "sp17_a_var_ema_dir",
category: ResetCategory::FoldReset,
description: "ISV[A_VAR_EMA_DIR_INDEX=474] — SP17 per-branch EMA of the over-actions variance of the centered advantage `A_centered[a, z] = A[a, z] mean_a A[a, z]` for the direction branch (4 actions: Long/Short/Hold/Flat). Diagnostic only; signals dueling-Q identifiability health (Var → 0 = `all actions equivalent, V dominates` = pre-SP17 pathology re-emerging; Var > 0 with stable V_share ≈ 0.5 = healthy decomposition). FoldReset sentinel SENTINEL_A_VAR_EMA=0.0 — Pearl-A first-observation bootstrap per `pearl_first_observation_bootstrap.md`. Producer + consumer wire in Phase 1-3 of SP17 (atomic across compute_expected_q + c51_loss + c51_grad + mag_concat_qdir mean-centering) — not yet wired in this commit. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_a_var_ema_mag",
category: ResetCategory::FoldReset,
description: "ISV[A_VAR_EMA_MAG_INDEX=475] — SP17 per-branch EMA of the over-actions variance of `A_centered` for the magnitude branch (Quarter/Half/Full). Same contract/sentinel as slot 474. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_a_var_ema_ord",
category: ResetCategory::FoldReset,
description: "ISV[A_VAR_EMA_ORD_INDEX=476] — SP17 per-branch EMA of the over-actions variance of `A_centered` for the order branch. Same contract/sentinel as slot 474. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_a_var_ema_urg",
category: ResetCategory::FoldReset,
description: "ISV[A_VAR_EMA_URG_INDEX=477] — SP17 per-branch EMA of the over-actions variance of `A_centered` for the urgency branch. Same contract/sentinel as slot 474. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_v_share_dir",
category: ResetCategory::FoldReset,
description: "ISV[V_SHARE_DIR_INDEX=478] — SP17 per-branch magnitude share `|V_contribution| / (|V_contribution| + |A_centered|)` for the direction branch. Diagnostic only; signals dueling-Q identifiability health (V_share → 1.0 with Var(A_centered) → 0 = pre-SP17 V-dominated pathology). FoldReset sentinel SENTINEL_V_SHARE=0.5 — Pearl-A bootstrap interpreted as cold-start `healthy 50/50 split` (rather than 0.0) so the diagnostic chain doesn't flag the very first launch as pathological before any observation has landed. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_v_share_mag",
category: ResetCategory::FoldReset,
description: "ISV[V_SHARE_MAG_INDEX=479] — SP17 per-branch magnitude share for the magnitude branch. Same contract/sentinel as slot 478. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_v_share_ord",
category: ResetCategory::FoldReset,
description: "ISV[V_SHARE_ORD_INDEX=480] — SP17 per-branch magnitude share for the order branch. Same contract/sentinel as slot 478. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_v_share_urg",
category: ResetCategory::FoldReset,
description: "ISV[V_SHARE_URG_INDEX=481] — SP17 per-branch magnitude share for the urgency branch. Same contract/sentinel as slot 478. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
RegistryEntry {
name: "sp17_advantage_clip_bound",
category: ResetCategory::FoldReset,
description: "ISV[ADVANTAGE_CLIP_BOUND_INDEX=482] — SP17 adaptive |A_centered| upper bound, producer-tracked from `p99(|A_centered|) × ADVANTAGE_CLIP_SAFETY_FACTOR=1.5` (mirrors SP14 P0-A REWARD_POS_CAP producer pattern). FoldReset sentinel SENTINEL_ADVANTAGE_CLIP_BOUND=1.0 — Pearl-A bootstrap interpreted as cold-start `no effective clipping` (1.0 ≫ typical |A_centered| early in training when A → 0; clip is a no-op until the first valid observation lands a real bound). α=ADVANTAGE_CLIP_EMA_ALPHA=0.01 slow per-fold cadence — the bound shouldn't track per-batch noise. Bilateral clamp to `[ADVANTAGE_CLIP_BOUND_MIN=0.1, ADVANTAGE_CLIP_BOUND_MAX=100.0]` per `pearl_symmetric_clamp_audit.md` — Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`: floor 0.1 below which centered advantage is essentially noise (clipping would erase the action signal); ceiling 100.0 above which a single adversarial outlier dominates per-batch EMAs. NEVER hardcoded — adaptive bound. Producer + consumer wire in Phase 1-3 of SP17 (atomic) — not yet wired. Plan: docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.",
},
];
Self { entries }
}

View File

@@ -8720,6 +8720,87 @@ impl DQNTrainer {
fused.trainer().write_isv_signal_at(MHT_SAMPLE_COUNT_INDEX, SENTINEL_WELFORD_ZERO);
}
}
// ── SP17 (2026-05-08): dueling-Q identifiability diagnostic slots
// [474..483). Pearl-A first-observation bootstrap. Producers /
// consumers wire in Phase 1-3 atomically per
// `feedback_no_partial_refactor`; this PP.2 commit is additive
// infrastructure only. Plan:
// docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md.
"sp17_a_var_ema_dir" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
A_VAR_EMA_DIR_INDEX, SENTINEL_A_VAR_EMA,
};
fused.trainer().write_isv_signal_at(A_VAR_EMA_DIR_INDEX, SENTINEL_A_VAR_EMA);
}
}
"sp17_a_var_ema_mag" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
A_VAR_EMA_MAG_INDEX, SENTINEL_A_VAR_EMA,
};
fused.trainer().write_isv_signal_at(A_VAR_EMA_MAG_INDEX, SENTINEL_A_VAR_EMA);
}
}
"sp17_a_var_ema_ord" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
A_VAR_EMA_ORD_INDEX, SENTINEL_A_VAR_EMA,
};
fused.trainer().write_isv_signal_at(A_VAR_EMA_ORD_INDEX, SENTINEL_A_VAR_EMA);
}
}
"sp17_a_var_ema_urg" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
A_VAR_EMA_URG_INDEX, SENTINEL_A_VAR_EMA,
};
fused.trainer().write_isv_signal_at(A_VAR_EMA_URG_INDEX, SENTINEL_A_VAR_EMA);
}
}
"sp17_v_share_dir" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
V_SHARE_DIR_INDEX, SENTINEL_V_SHARE,
};
fused.trainer().write_isv_signal_at(V_SHARE_DIR_INDEX, SENTINEL_V_SHARE);
}
}
"sp17_v_share_mag" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
V_SHARE_MAG_INDEX, SENTINEL_V_SHARE,
};
fused.trainer().write_isv_signal_at(V_SHARE_MAG_INDEX, SENTINEL_V_SHARE);
}
}
"sp17_v_share_ord" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
V_SHARE_ORD_INDEX, SENTINEL_V_SHARE,
};
fused.trainer().write_isv_signal_at(V_SHARE_ORD_INDEX, SENTINEL_V_SHARE);
}
}
"sp17_v_share_urg" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
V_SHARE_URG_INDEX, SENTINEL_V_SHARE,
};
fused.trainer().write_isv_signal_at(V_SHARE_URG_INDEX, SENTINEL_V_SHARE);
}
}
"sp17_advantage_clip_bound" => {
if let Some(ref fused) = self.fused_ctx {
use crate::cuda_pipeline::sp14_isv_slots::{
ADVANTAGE_CLIP_BOUND_INDEX, SENTINEL_ADVANTAGE_CLIP_BOUND,
};
fused.trainer().write_isv_signal_at(
ADVANTAGE_CLIP_BOUND_INDEX,
SENTINEL_ADVANTAGE_CLIP_BOUND,
);
}
}
// SP15 Phase 1.2 (2026-05-06): cost-net sharpe slots.
// OFI_IMPACT_LAMBDA_INDEX=407 is an Invariant-1 anchor (NOT
// a stateful EMA) — rewrite the constructor's value at fold

View File

@@ -2,6 +2,52 @@
**Status:** Populated during Plan 1 Task 6 (A.5 orphan audit). Updated on every commit per Invariant 7.
## 2026-05-08 — SP17 Task PP.2: dueling-Q identifiability ISV slots [474..483)
Allocates the 9 ISV slots that drive the SP17 dueling-Q identifiability diagnostic chain. **Additive infrastructure only — no consumer wiring in this commit.** The Phase 1 mean-centering producer (atomic across `compute_expected_q` + `c51_loss` + `c51_grad` + `mag_concat_qdir`) lands in the next 4 commits per `feedback_no_partial_refactor`.
### Why SP17
The codebase has separate V-head (`on_v_logits_buf`) and per-branch A-head (`on_b_logits_buf`) buffers, but combines them naively as `logit = v_row[z] + adv_a[z]` — no `A mean_a A` subtraction. This is over-parameterization without identifiability: the optimizer is mathematically free to learn the degenerate `V ≈ Q(Flat), A ≈ Q(a) Q(Flat)` decomposition, which IS the Q(Flat) attractor we have been fighting since SP11. The fix is small and surgical: insert mean-zero projection at 4 existing aggregation sites (Phase 1-3). PP.2 lays the ISV slot infrastructure for the diagnostics that observe whether the projection is doing real work.
### Slot inventory (9 slots, [474..483))
| Slot | Name | Role | Sentinel | Bounds |
|------|------|------|----------|--------|
| 474 | `A_VAR_EMA_DIR_INDEX` | Var(A_centered) over dir actions, EMA | 0.0 (Pearl-A) | — |
| 475 | `A_VAR_EMA_MAG_INDEX` | Var(A_centered) over mag actions, EMA | 0.0 (Pearl-A) | — |
| 476 | `A_VAR_EMA_ORD_INDEX` | Var(A_centered) over ord actions, EMA | 0.0 (Pearl-A) | — |
| 477 | `A_VAR_EMA_URG_INDEX` | Var(A_centered) over urg actions, EMA | 0.0 (Pearl-A) | — |
| 478 | `V_SHARE_DIR_INDEX` | `\|V\| / (\|V\| + \|A_centered\|)` for dir | 0.5 (cold-start 50/50) | — |
| 479 | `V_SHARE_MAG_INDEX` | same for mag | 0.5 | — |
| 480 | `V_SHARE_ORD_INDEX` | same for ord | 0.5 | — |
| 481 | `V_SHARE_URG_INDEX` | same for urg | 0.5 | — |
| 482 | `ADVANTAGE_CLIP_BOUND_INDEX` | adaptive `\|A_centered\|` upper bound | 1.0 (no effective clipping) | [0.1, 100.0] |
**Producer (Phase 1, not yet landed):** `advantage_clip_bound_update_kernel` computes `p99(|A_centered|) × ADVANTAGE_CLIP_SAFETY_FACTOR=1.5` (mirrors SP14 P0-A REWARD_POS_CAP producer pattern), bilateral-clamps to `[ADVANTAGE_CLIP_BOUND_MIN=0.1, ADVANTAGE_CLIP_BOUND_MAX=100.0]` per `pearl_symmetric_clamp_audit`, slow-EMA blends with `ADVANTAGE_CLIP_EMA_ALPHA=0.01`. Per `feedback_isv_for_adaptive_bounds`: producer-tracked, NEVER hardcoded.
**Consumers (Phase 1-3, not yet landed):** mean-zero projection at 4 sites in atomic migration — `compute_expected_q`, `c51_loss`, `c51_grad`, `mag_concat_qdir`. The 9 diagnostic slots are read by HEALTH_DIAG (Phase 5).
### Files modified in PP.2
- `crates/ml/src/cuda_pipeline/sp14_isv_slots.rs` — 9 slot constants + sentinels + bounds + 2 lock-tests appended after SP16 T3 block.
- `crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs``ISV_TOTAL_DIM` 474 → 483 + `layout_fingerprint_seed` extended with 9 new `SLOT_<N>_<NAME>=<N>` lines.
- `crates/ml/src/trainers/dqn/state_reset_registry.rs` — 9 `RegistryEntry { ResetCategory::FoldReset, ... }` entries appended at the end of `new()`.
- `docs/dqn-wire-up-audit.md` — this section.
### Why no `state_layout.cuh` mirror update
`state_layout.cuh::ISV_TOTAL_DIM` is a stale historical marker (currently 383) per its own comment block at line 260-266 — `kernels take const float* pointers and use raw indices, no .cu/.cuh file dimensions an array with this macro. The Rust constant is the single source of truth for the bus size.` No-op for this PP.2.
### Verification
```
SQLX_OFFLINE=true cargo test -p ml --lib sp17_dueling_slot_layout_locked all_sp17_slots_fit_within_isv_total_dim → PASS (2/2)
SQLX_OFFLINE=true CUDA_COMPUTE_CAP=86 cargo check --workspace → clean
```
Plan: `docs/superpowers/plans/2026-05-08-sp17-dueling-q-network.md` Task PP.2.
## 2026-05-08 — Class A audit-fix Batch 4-B: plan_threshold floor adaptive + MIN_HOLD_TEMPERATURE ISV-driven
Per Class A audit-fix Batch 4-B (final 2 of 4 deferred items from P1-wiring/P1-producer). Completes the 8-commit WR-plateau intervention chain. Validation deferred to next L40S smoke.