Pure observability. No behavior change. Implements the missing
"short-run trust adjustment" layer between Kelly long-run sizing and
CMDP tail kill, per pearl_edge_decay_detection_is_a_missing_abstraction_layer.
The 64 commits since dd049d9a4 added tail-event circuit breakers (CMDP DD,
Kelly trap, IQN-τ); none addressed slow-bleed via overtrading on degraded
edge. alpha-rl-glv6n showed eval pnl -$24.85M came from 47K trades at
wr=0.256 with 95 closes/step — 2000× higher close rate than train —
invisible to all existing risk machinery because no single trade tripped
a tail-event threshold.
Page-Hinkley change-point detector on σ_welford-normalized per-trade PnL:
x_t = rewards[b] / σ_welford (slot 725, scale-invariant)
μ̄_t = pre-update Welford running mean
m_t = m_{t-1} + (x_t − μ̄_pre − δ) [only after warmup]
M_t = min(M_{t-1}, m_t) [only after warmup]
ph_stat_t = m_t − M_t
ISV slots (6 new, 747-752): δ=0.1, λ=5.0, warmup_min=10 (σ-relative
unit-less); fleet aggregates ph_mean (over active batches),
frac_ph_alerted (n_alerted/n_active), frac_ph_warmup (n_warmup/b_size).
Per-batch device buffers (5 new): ph_mu/count/m/mmin/stat. Read+written
only by rl_cmdp_constraints_check kernel.
Reset discipline: all 5 PH buffers added to reset_session_state memset
block alongside existing CMDP per-batch state. PH is PREDICTIVE (predicts
future edge degradation from recent trajectory), so it follows
"RESET PREDICTIVE, PRESERVE NORMALIZATION" per
pearl_popart_reset_at_eval_boundary_shocks_normalization. σ_welford
itself is normalization — it lives in popart EMA which IS preserved
across boundaries.
Kernel ordering note: rl_cmdp_constraints_check fires BEFORE
apply_reward_scale and rl_popart_normalize, so rewards[b] at kernel
entry is RAW USD and the σ slot read is the prior step's σ_welford
(one-step lag, acceptable for diagnostic). Slot 725 chosen over slot 555
(σ_effective) because slot 555 spikes 1000× at the eval shock window —
blinding the detector exactly when bleed is largest.
EXPECTED_LEAVES bump 675 → 678 (+3 diag leaves
edge_ph_{mean,frac_alerted,frac_warmup}).
Local b=16 smoke (100+50): wiring validated. Train phase by step 99
shows ph_mean=3.5 (close to λ=5), frac_alerted=0.25 — detector
firing as designed at active batches. Eval[0] frac_warmup snaps back to
1.0 — confirms reset_session_state extension correctly zeroed all 5
PH buffers at fold/eval boundary (BLOCKER #1 contract validated).
Predetermined falsification (cluster smoke b=1024, per spec §G5):
- frac_ph_warmup drops <0.4 by train step 1000 AND eval step 200
(≥35% cooldown-suppressed tail acknowledged)
- frac_ph_warmup snaps to ≥0.95 at first eval row (reset wiring test)
- ph_mean rises from <1 to >3 over first 200 eval trades
- frac_ph_alerted > 0.3 by eval step 300
3-strike abandonment: if 3 V2 iterations fail for 3 different parameter
reasons, audit signal source (per feedback_going_in_circles_pattern).
Spec: docs/superpowers/specs/2026-06-01-edge-decay-detector-phase1-diagnostic.md
(v3 after 3 sp-critical-reviewer passes; verdict GO after final review).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>