plan(sp18 v2): allocate 22 ISV slots [483..505) for D-leg + B-leg

Adds combined SP18 D-leg Hold-reward adaptive-cap slots [483..493) +
B-leg TD(λ) Q(s') bootstrap diagnostics + PopArt reset flag at
[493..505) per spec DD6 (D-leg 10 slots) + B-DD13 (B-leg 12 slots).

D-leg [483..493) — 10 slots:
  483 HOLD_REWARD_POS_CAP            (sentinel 5.0,  bounds [0.5, 50])
  484 HOLD_REWARD_NEG_CAP            (sentinel -10.0)
  485 HOLD_REWARD_DECOMP_DIAG        (sentinel 0.0)
  486 HOLD_OPP_COST_FIRE_RATE_EMA    (sentinel 0.0)
  487..493 HRC_* Welford accumulators (mirrors SP16 T3 HCS_* pattern)

B-leg [493..505) — 12 slots:
  493 TD_ERROR_MAG_EMA               (HEALTH_DIAG B-DD9 ratio gate input)
  494 Q_NEXT_TARGET_P99              (target-Q bootstrap bound check)
  495 Q_NEXT_MINUS_REWARD_P99        (sanity: should be O(1) post-fix)
  496 V_SHARE_TREND_DIAG             (B-leg synergy probe)
  497 POPART_RESET_FLAG              (sentinel 1.0 — one-shot, B-DD11)
  498..504 TDB_* Welford accumulators (mirrors HRC_* pattern)
  504 RESERVED                        (B-leg follow-up)

Pearl-A first-observation bootstrap sentinels match position-side
SP14 P0-A REWARD_POS_CAP_ADAPTIVE pattern (POS=5.0, NEG=-10.0). Slot
497 POPART_RESET_FLAG sentinel = 1.0 per B-DD11 — host writes 1.0
once at first SP18 epoch, kernel zeroes after consuming, gating the
per-fold PopArt slot 63 EMA reset at the SP18 deployment boundary.

ISV_TOTAL_DIM bumped 483 → 505; layout_fingerprint_seed updated with
all 22 new slot names; state_layout.cuh C-side mirror in lockstep
(continues SP14-P0A/P1/audit-fix-4A/4B mirror precedent — SP16/SP17
slots intentionally not mirrored per existing pattern, only SP18 gets
fresh mirror entries).

`feedback_no_partial_refactor`: both legs share an ISV section + a
single fingerprint bump; SP13 [380..383) and SP16 [461..474) slots
remain ALLOCATED but RETIRED in PP.4 (sentinel 0.0, no producer
launch — RESERVED-gap pattern from SP14-C.1 preserves checkpoint
compatibility).

Audit doc updated per Invariant 7 with Pre-Phase PP.2 entry.

Spec: docs/superpowers/specs/2026-05-08-sp18-reward-shape-hold-attractor-design.md
Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-05-09 00:34:13 +02:00
parent 44e1f58b69
commit 16100912c3
4 changed files with 373 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -680,6 +680,157 @@ 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;
// ── SP18 (2026-05-08) — combined Hold-attractor fix: D-leg + B-leg ─────
// 22 ISV slots [483..505) split across two legs per the v2 combined plan:
//
// D-leg [483..493) — 10 slots (DD6).
// B-leg [493..505) — 12 slots (B-DD13, including 1 RESERVED).
//
// D-leg ("structural Hold opportunity-cost reward")
// ──────────────────────────────────────────────────
// Replaces the SP13 P0a + SP16 P2 + SP16 T3 reactive per-bar Hold-cost
// chain (per DD7=c) with a structural reward at the 3 Hold-cost
// subtraction sites in `experience_kernels.cu`. Each Hold-action bar pays
// `compute_sp18_hold_opportunity_cost(-2 × vol_normalized_next_log_return,
// neg_cap, pos_cap, shaping_scale)` — a counterfactual cost in the
// realised next-bar log-return units, asymmetric-capped via the new
// adaptive producer kernel `hold_reward_cap_update_kernel.cu`.
//
// [483] HOLD_REWARD_POS_CAP upper bound on positive Hold reward
// (Hold during a losing bar)
// [484] HOLD_REWARD_NEG_CAP lower bound on negative Hold reward
// (Hold during a winning bar — opp cost)
// [485] HOLD_REWARD_DECOMP_DIAG HEALTH_DIAG: per-action-bin reward
// decomposition diagnostic (Phase 0)
// [486] HOLD_OPP_COST_FIRE_RATE_EMA fraction of bars with non-zero
// Hold opp-cost reward (engagement
// canary — should be ≈ Hold% itself)
// [487..493) HRC_* Welford accumulators for Wiener-α
// EMA blend (mirrors SP16 T3 HCS_*
// layout — 6 slots)
//
// Cap producer (Phase 3): reads `p99(|step_ret|)` over Long/Short trade
// closes (DD3=b), multiplies by HOLD_REWARD_CAP_SAFETY_FACTOR=1.5, writes
// POS=that and NEG=2 × POS (DD5=b mirrored asymmetry — same 2:1
// loss-aversion ratio as SP14 P0-A REWARD_POS/NEG_CAP). Wiener-optimal α
// from the Welford accumulators in [487..493) per
// `pearl_wiener_optimal_adaptive_alpha`.
//
// Pearl-A first-observation bootstrap sentinels POS=5.0 / NEG=10.0
// match the position-side SP14 P0-A REWARD_POS/NEG_CAP_ADAPTIVE pattern
// for bit-identical cold-start before the first valid producer launch
// lands a real cap. Bounds [POS_MIN=0.5, POS_MAX=50.0] are Category-1
// dimensional safety floors per `feedback_isv_for_adaptive_bounds.md`.
//
// SP13 [380..383)/SP16 [461..474) slots remain ALLOCATED but RETIRED per
// PP.4 — sentinel 0.0, no producer launch. Slots stay in the layout
// fingerprint to preserve checkpoint compatibility (RESERVED-gap pattern
// established at SP14-C.1).
//
// Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md
pub const HOLD_REWARD_POS_CAP_INDEX: usize = 483;
pub const HOLD_REWARD_NEG_CAP_INDEX: usize = 484;
pub const HOLD_REWARD_DECOMP_DIAG_INDEX: usize = 485;
pub const HOLD_OPP_COST_FIRE_RATE_EMA_INDEX: usize = 486;
pub const HRC_TARGET_MEAN_INDEX: usize = 487; // Welford running mean of target_cap
pub const HRC_TARGET_M2_INDEX: usize = 488; // Welford ΣΔ² (sample variance)
pub const HRC_DIFF_MEAN_INDEX: usize = 489; // Welford running mean of consecutive diffs
pub const HRC_DIFF_M2_INDEX: usize = 490; // Welford ΣΔ² for diff series
pub const HRC_PREV_TARGET_INDEX: usize = 491; // previous-epoch target_cap (for diff)
pub const HRC_SAMPLE_COUNT_INDEX: usize = 492; // Welford counter
// Sentinels — Pearl-A first-observation bootstrap. POS=5.0 / NEG=-10.0
// match the SP14 P0-A REWARD_POS/NEG_CAP_ADAPTIVE pattern (bit-identical
// cold-start to the position-side adaptive cap). DIAG / FIRE_RATE bootstrap
// to 0.0 — Pearl-A direct-replace on first valid observation.
pub const SENTINEL_HOLD_REWARD_POS_CAP: f32 = 5.0;
pub const SENTINEL_HOLD_REWARD_NEG_CAP: f32 = -10.0;
pub const SENTINEL_HOLD_REWARD_DIAG: f32 = 0.0;
pub const SENTINEL_HOLD_OPP_FIRE_RATE: f32 = 0.0;
// Category-1 dimensional safety bounds per `feedback_isv_for_adaptive_bounds`.
// Floor 0.5: below this any positive Hold reward is essentially noise; the
// asymmetric ratio NEG=-2×POS would drop NEG below -1, smaller than typical
// per-bar reward magnitudes. Ceiling 50.0: above this a single adversarial
// outlier from the Long/Short close p99 can dominate the EMA. Mirrors the
// SP14 P0-A REWARD_POS_CAP_MIN/MAX pattern.
pub const HOLD_REWARD_POS_CAP_MIN_BOUND: f32 = 0.5;
pub const HOLD_REWARD_POS_CAP_MAX_BOUND: f32 = 50.0;
// Producer constants. Safety factor 1.5× p99 mirrors the SP14 P0-A
// REWARD_POS_CAP producer pattern. EMA α is Wiener-optimal per
// `pearl_wiener_optimal_adaptive_alpha` (Welford accumulators in
// [487..493)) — no hardcoded constant.
pub const HOLD_REWARD_CAP_SAFETY_FACTOR: f32 = 1.5;
pub const SP18_HOLD_REWARD_SLOT_BASE: usize = 483;
pub const SP18_HOLD_REWARD_SLOT_END: usize = 493;
// B-leg ("TD(λ) Q(s') bootstrap")
// ──────────────────────────────────
// Replaces the `q_next = rewards` self-bootstrap at
// `gpu_experience_collector.rs:4143` with a real per-branch DDQN
// `Q_target(s', argmax_a Q_online(s', a))` computed by a target-net
// forward pass on `next_states` at experience-collection time. Reuses
// existing `target_params_buf` (SP14 P4.T1B-iv Polyak-tracked) — no new
// target-net infra (B-DD1).
//
// [493] TD_ERROR_MAG_EMA HEALTH_DIAG: avg(|TD-error|) post-fix
// (B-DD9 ratio gate input)
// [494] Q_NEXT_TARGET_P99 p99 of target-Q bootstrap (bound
// sanity check on the new path)
// [495] Q_NEXT_MINUS_REWARD_P99 p99 of |q_next_target rewards|
// (sanity: should be O(1) post-fix —
// proves the fix is doing something
// AND not blowing up)
// [496] V_SHARE_TREND_DIAG slope of V_SHARE EMA across last 4
// epochs (B-leg synergy probe — the
// bootstrap-bias hypothesis predicts
// v_share monotone HD0→HD4)
// [497] POPART_RESET_FLAG 1.0 first epoch post-deployment;
// 0.0 thereafter (B-DD11 — gates the
// per-fold PopArt slot 63 EMA reset
// at the SP18 deployment boundary).
// NOT a FoldReset — host writes 1.0
// once at deploy, kernel zeroes it
// after consuming.
// [498..504) TDB_* Welford accumulators for Wiener-α
// EMA blend on q_next_target stats
// (mirrors HRC_* layout — 6 slots)
// [504] RESERVED reserved for B-leg follow-up
//
// Pearl-A first-observation bootstrap sentinels match the canonical
// pattern: TD/Q/V_SHARE_TREND diagnostic slots → 0.0; POPART_RESET_FLAG
// → 1.0 (one-shot signalling first SP18-deployment epoch).
//
// Spec §B-DD12 (HEALTH_DIAG observability) + §B-DD13 (slot allocation)
// + §B-DD11 (PopArt reset gate).
pub const TD_ERROR_MAG_EMA_INDEX: usize = 493;
pub const Q_NEXT_TARGET_P99_INDEX: usize = 494;
pub const Q_NEXT_MINUS_REWARD_P99_INDEX: usize = 495;
pub const V_SHARE_TREND_DIAG_INDEX: usize = 496;
pub const POPART_RESET_FLAG_INDEX: usize = 497;
pub const TDB_TARGET_MEAN_INDEX: usize = 498;
pub const TDB_TARGET_M2_INDEX: usize = 499;
pub const TDB_DIFF_MEAN_INDEX: usize = 500;
pub const TDB_DIFF_M2_INDEX: usize = 501;
pub const TDB_PREV_TARGET_INDEX: usize = 502;
pub const TDB_SAMPLE_COUNT_INDEX: usize = 503;
pub const SP18_B_LEG_RESERVED_INDEX: usize = 504;
// Sentinels — Pearl-A first-observation bootstrap. Diagnostic slots
// (493, 494, 495, 496) bootstrap to 0.0 — Pearl-A direct-replace on
// first valid observation. POPART_RESET_FLAG=1.0 (one-shot — gates the
// per-fold PopArt slot 63 EMA reset on the first SP18 epoch per B-DD11).
pub const SENTINEL_TD_ERROR_MAG_EMA: f32 = 0.0;
pub const SENTINEL_Q_NEXT_TARGET_P99: f32 = 0.0;
pub const SENTINEL_Q_NEXT_MINUS_REWARD_P99: f32 = 0.0;
pub const SENTINEL_V_SHARE_TREND_DIAG: f32 = 0.0;
pub const SENTINEL_POPART_RESET_FLAG: f32 = 1.0; // one-shot ⇒ PopArt reset at first SP18 epoch
pub const SP18_TD_BOOTSTRAP_SLOT_BASE: usize = 493;
pub const SP18_TD_BOOTSTRAP_SLOT_END: usize = 505;
#[cfg(test)]
mod tests {
use super::*;
@@ -1057,4 +1208,76 @@ mod tests {
SP17_DUELING_SLOT_END, ISV_TOTAL_DIM,
);
}
/// Lock SP18 (2026-05-08 v2 combined) D-leg + B-leg slot layout.
/// 22 contiguous slots [483..505): 10 D-leg + 12 B-leg. Per
/// `feedback_no_partial_refactor`, both legs share an ISV section
/// and a single layout fingerprint bump — combined SP18 lands all 22
/// slots atomically in Pre-Phase before Phase 0+ wiring.
#[test]
fn sp18_combined_slot_layout_locked() {
// ── D-leg [483..493) ─────────────────────────────────────────
assert_eq!(SP18_HOLD_REWARD_SLOT_BASE, 483);
assert_eq!(SP18_HOLD_REWARD_SLOT_END, 493);
assert_eq!(HOLD_REWARD_POS_CAP_INDEX, 483);
assert_eq!(HOLD_REWARD_NEG_CAP_INDEX, 484);
assert_eq!(HOLD_REWARD_DECOMP_DIAG_INDEX, 485);
assert_eq!(HOLD_OPP_COST_FIRE_RATE_EMA_INDEX, 486);
assert_eq!(HRC_TARGET_MEAN_INDEX, 487);
assert_eq!(HRC_TARGET_M2_INDEX, 488);
assert_eq!(HRC_DIFF_MEAN_INDEX, 489);
assert_eq!(HRC_DIFF_M2_INDEX, 490);
assert_eq!(HRC_PREV_TARGET_INDEX, 491);
assert_eq!(HRC_SAMPLE_COUNT_INDEX, 492);
// ── B-leg [493..505) ─────────────────────────────────────────
assert_eq!(SP18_TD_BOOTSTRAP_SLOT_BASE, 493);
assert_eq!(SP18_TD_BOOTSTRAP_SLOT_END, 505);
assert_eq!(TD_ERROR_MAG_EMA_INDEX, 493);
assert_eq!(Q_NEXT_TARGET_P99_INDEX, 494);
assert_eq!(Q_NEXT_MINUS_REWARD_P99_INDEX, 495);
assert_eq!(V_SHARE_TREND_DIAG_INDEX, 496);
assert_eq!(POPART_RESET_FLAG_INDEX, 497);
assert_eq!(TDB_TARGET_MEAN_INDEX, 498);
assert_eq!(TDB_TARGET_M2_INDEX, 499);
assert_eq!(TDB_DIFF_MEAN_INDEX, 500);
assert_eq!(TDB_DIFF_M2_INDEX, 501);
assert_eq!(TDB_PREV_TARGET_INDEX, 502);
assert_eq!(TDB_SAMPLE_COUNT_INDEX, 503);
assert_eq!(SP18_B_LEG_RESERVED_INDEX, 504);
// ── Sentinels — Pearl-A first-observation bootstrap (D-leg) ──
assert_eq!(SENTINEL_HOLD_REWARD_POS_CAP, 5.0);
assert_eq!(SENTINEL_HOLD_REWARD_NEG_CAP, -10.0);
assert_eq!(SENTINEL_HOLD_REWARD_DIAG, 0.0);
assert_eq!(SENTINEL_HOLD_OPP_FIRE_RATE, 0.0);
// ── Sentinels — B-leg ─────────────────────────────────────────
assert_eq!(SENTINEL_TD_ERROR_MAG_EMA, 0.0);
assert_eq!(SENTINEL_Q_NEXT_TARGET_P99, 0.0);
assert_eq!(SENTINEL_Q_NEXT_MINUS_REWARD_P99, 0.0);
assert_eq!(SENTINEL_V_SHARE_TREND_DIAG, 0.0);
assert_eq!(SENTINEL_POPART_RESET_FLAG, 1.0); // 1.0 first epoch ⇒ PopArt reset (B-DD11)
// ── Bounds (D-leg, Category-1 floors) ────────────────────────
assert_eq!(HOLD_REWARD_POS_CAP_MIN_BOUND, 0.5);
assert_eq!(HOLD_REWARD_POS_CAP_MAX_BOUND, 50.0);
// ── Producer constants ───────────────────────────────────────
assert_eq!(HOLD_REWARD_CAP_SAFETY_FACTOR, 1.5);
}
/// Asserts SP18 combined slot range fits within ISV_TOTAL_DIM.
/// Mirrors the SP17 / SP14 / SP5 pattern. The contract test fails
/// with a clear actionable message before any consumer can drift.
#[test]
fn all_sp18_slots_fit_within_isv_total_dim() {
use crate::cuda_pipeline::gpu_dqn_trainer::ISV_TOTAL_DIM;
assert!(
SP18_TD_BOOTSTRAP_SLOT_END <= ISV_TOTAL_DIM,
"SP18_TD_BOOTSTRAP_SLOT_END={} exceeds ISV_TOTAL_DIM={}; \
bump ISV_TOTAL_DIM in gpu_dqn_trainer.rs (and update layout_fingerprint_seed()).",
SP18_TD_BOOTSTRAP_SLOT_END, ISV_TOTAL_DIM,
);
}
}

View File

@@ -469,6 +469,92 @@
// See the SP16 T3 SLOTS section above for the slot indices.
#define DIR_ACC_RANDOM_BASELINE 0.5f
// ── SP18 (2026-05-08) — combined Hold-attractor fix: D-leg + B-leg ────
// 22 ISV slots [483..505) split across two atomic legs per the v2
// combined plan. Mirrors `crates/ml/src/cuda_pipeline/sp14_isv_slots.rs`
// constants of the same names (locked by `sp18_combined_slot_layout_locked`
// test). Like SP16/SP17 mirrors, the C-side header tracks slot indices
// + sentinels + bounds for kernels that read the bus directly via raw
// indices; the Rust constant is the single source of truth (see
// ISV_TOTAL_DIM macro note above).
//
// D-leg ("structural Hold opportunity-cost reward") replaces the SP13
// P0a + SP16 P2 + SP16 T3 reactive per-bar Hold-cost chain (DD7=c) with
// a structural reward at the 3 Hold-cost subtraction sites in
// experience_kernels.cu via the new device function
// `compute_sp18_hold_opportunity_cost` (added to trade_physics.cuh in
// Phase 2). HOLD_REWARD_POS_CAP / HOLD_REWARD_NEG_CAP are adaptive bounds
// producer-tracked from p99(|step_ret|) over Long/Short trade closes ×
// HOLD_REWARD_CAP_SAFETY_FACTOR=1.5 (DD3=b) with NEG = -2 × POS
// (DD5=b mirrored loss-aversion).
//
// B-leg ("TD(λ) Q(s') bootstrap") replaces the q_next = rewards
// self-bootstrap at gpu_experience_collector.rs:4143 with a real
// per-branch DDQN `Q_target(s', argmax_a Q_online(s', a))` computed via
// target-net forward pass on next_states at experience-collection time
// (Phase 4-5). All B-leg slots are observability-only (HEALTH_DIAG
// diagnostics) plus the one-shot POPART_RESET_FLAG that gates the
// per-fold PopArt EMA reset at the SP18 deployment boundary (B-DD11).
//
// Plan: docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md
// D-leg slots [483..493) — 10 slots
#define HOLD_REWARD_POS_CAP_INDEX 483
#define HOLD_REWARD_NEG_CAP_INDEX 484
#define HOLD_REWARD_DECOMP_DIAG_INDEX 485
#define HOLD_OPP_COST_FIRE_RATE_EMA_INDEX 486
#define HRC_TARGET_MEAN_INDEX 487
#define HRC_TARGET_M2_INDEX 488
#define HRC_DIFF_MEAN_INDEX 489
#define HRC_DIFF_M2_INDEX 490
#define HRC_PREV_TARGET_INDEX 491
#define HRC_SAMPLE_COUNT_INDEX 492
// D-leg sentinels — Pearl-A first-observation bootstrap. POS=5.0 /
// NEG=-10.0 match the SP14 P0-A REWARD_POS/NEG_CAP_ADAPTIVE pattern
// (bit-identical cold-start to the position-side adaptive cap).
#define SENTINEL_HOLD_REWARD_POS_CAP 5.0f
#define SENTINEL_HOLD_REWARD_NEG_CAP -10.0f
#define SENTINEL_HOLD_REWARD_DIAG 0.0f
#define SENTINEL_HOLD_OPP_FIRE_RATE 0.0f
// D-leg defensive consumer-side bounds (mirror Rust constants
// HOLD_REWARD_POS_CAP_MIN/MAX_BOUND in sp14_isv_slots.rs). Values
// outside this window fall back to sentinels on the consumer side as a
// defense against malformed prior state. Producer kernel clamps to the
// same range, so a healthy ISV slot will always pass the guard.
#define HOLD_REWARD_POS_CAP_MIN_BOUND 0.5f
#define HOLD_REWARD_POS_CAP_MAX_BOUND 50.0f
// D-leg producer constant. Safety factor 1.5× p99 mirrors the SP14 P0-A
// REWARD_POS_CAP producer pattern.
#define HOLD_REWARD_CAP_SAFETY_FACTOR 1.5f
// B-leg slots [493..505) — 12 slots
#define TD_ERROR_MAG_EMA_INDEX 493
#define Q_NEXT_TARGET_P99_INDEX 494
#define Q_NEXT_MINUS_REWARD_P99_INDEX 495
#define V_SHARE_TREND_DIAG_INDEX 496
#define POPART_RESET_FLAG_INDEX 497
#define TDB_TARGET_MEAN_INDEX 498
#define TDB_TARGET_M2_INDEX 499
#define TDB_DIFF_MEAN_INDEX 500
#define TDB_DIFF_M2_INDEX 501
#define TDB_PREV_TARGET_INDEX 502
#define TDB_SAMPLE_COUNT_INDEX 503
#define SP18_B_LEG_RESERVED_INDEX 504
// B-leg sentinels — Pearl-A first-observation bootstrap. Diagnostic
// slots bootstrap to 0.0 (direct-replace on first valid observation).
// POPART_RESET_FLAG sentinel = 1.0 (one-shot — gates the per-fold
// PopArt slot 63 EMA reset on the first SP18 epoch per B-DD11; host
// writes 1.0 at deploy, kernel zeroes after consuming).
#define SENTINEL_TD_ERROR_MAG_EMA 0.0f
#define SENTINEL_Q_NEXT_TARGET_P99 0.0f
#define SENTINEL_Q_NEXT_MINUS_REWARD_P99 0.0f
#define SENTINEL_V_SHARE_TREND_DIAG 0.0f
#define SENTINEL_POPART_RESET_FLAG 1.0f
// ── Compile-time checks ──
static_assert(SL_PADDING_START + SL_PADDING_DIM == SL_STATE_DIM,
"State layout dimensions must sum to SL_STATE_DIM");

View File

@@ -2,6 +2,46 @@
**Status:** Populated during Plan 1 Task 6 (A.5 orphan audit). Updated on every commit per Invariant 7.
## 2026-05-08 — SP18 v2 Pre-Phase Task PP.2: 22 ISV slots [483..505) D-leg + B-leg
Pre-Phase scaffolding for the combined SP18 v2 plan: allocates 22 ISV slots split across two atomic legs per `feedback_no_partial_refactor`.
**D-leg [483..493) — 10 slots** ("structural Hold opportunity-cost reward"):
| Slot | Name | Sentinel | Notes |
|---|---|---|---|
| 483 | `HOLD_REWARD_POS_CAP` | 5.0 | Pearl-A; matches SP14 P0-A REWARD_POS_CAP for bit-identical cold-start |
| 484 | `HOLD_REWARD_NEG_CAP` | -10.0 | Pearl-A; -2× POS preserves Kahneman 2:1 loss-aversion ratio |
| 485 | `HOLD_REWARD_DECOMP_DIAG` | 0.0 | HEALTH_DIAG observability — Phase 0 reward decomposition |
| 486 | `HOLD_OPP_COST_FIRE_RATE_EMA` | 0.0 | Engagement canary — should be ≈ Hold% itself |
| 487..493 | 6 `HRC_*` Welford accumulators | 0.0 | Mirrors SP16 T3 `HCS_*` Wiener-α layout |
**B-leg [493..505) — 12 slots** ("TD(λ) Q(s') bootstrap"):
| Slot | Name | Sentinel | Notes |
|---|---|---|---|
| 493 | `TD_ERROR_MAG_EMA` | 0.0 | HEALTH_DIAG observability — B-DD9 ratio-gate input (`avg(\|TD-error\|)`) |
| 494 | `Q_NEXT_TARGET_P99` | 0.0 | bound check on the new target-Q bootstrap |
| 495 | `Q_NEXT_MINUS_REWARD_P99` | 0.0 | sanity: should be O(1) post-fix (proves the fix is doing something AND not blowing up) |
| 496 | `V_SHARE_TREND_DIAG` | 0.0 | B-leg synergy probe (slope of V_SHARE EMA across last 4 epochs) |
| 497 | `POPART_RESET_FLAG` | **1.0** | one-shot, NOT a FoldReset; gates per-fold PopArt slot 63 EMA reset at SP18 deployment boundary per B-DD11 |
| 498..504 | 6 `TDB_*` Welford accumulators | 0.0 | Mirrors `HRC_*` Wiener-α layout |
| 504 | `RESERVED` | 0.0 | reserved for B-leg follow-up |
**Pearl pattern**: D-leg POS/NEG cap sentinels match the position-side SP14 P0-A `REWARD_POS_CAP_ADAPTIVE` pattern (5.0 / -10.0) for bit-identical cold-start before the cap producer (Phase 3) lands a real `p99(|step_ret|) × 1.5`. The B-leg POPART_RESET_FLAG=1.0 is the only non-zero sentinel — host writes 1.0 once at the SP18 deployment boundary, kernel zeroes after consuming (one-shot signalling, NOT a FoldReset).
**Bounds**: D-leg POS cap clamped to `[0.5, 50.0]` Category-1 dimensional safety floors per `feedback_isv_for_adaptive_bounds`. B-leg slots are observability-only (no bounds enforced — diagnostic readout only).
**ISV_TOTAL_DIM**: 483 → 505. `layout_fingerprint_seed` extended with 22 new `SLOT_*` entries. `state_layout.cuh` mirror added (continues SP14 P0-A/P1/audit-fix-4A/4B precedent — SP16/SP17 slots intentionally not mirrored, only SP18 gets fresh `#define`s for the device-side header).
**Atomicity envelope**: Pre-Phase scaffolding only — 22 ISV slots locked, fingerprint extended, mirror constants in C header. NO producer kernel, NO consumer wire-in, NO HEALTH_DIAG emit. Phase 0 (diagnostic emit), Phases 17 (consumer/producer), Phases 810 (validation) follow per the v2 plan.
**SP13/SP16 retirement**: Slots [380..383) (HOLD_COST + HOLD_RATE_TARGET + HOLD_RATE_OBSERVED_EMA) and [461..474) (HOLD_COST_SCALE + Welford accumulators) remain ALLOCATED but will be RETIRED in PP.4 (sentinel 0.0, no producer launch) per the SP14-C.1 RESERVED-gap pattern — preserves checkpoint compatibility while DD7=c replaces the reactive per-bar Hold-cost chain with the structural opportunity-cost reward.
**Plan**: `docs/superpowers/plans/2026-05-08-sp18-reward-shape-hold-attractor.md` § Pre-Phase Task PP.2.
**Spec**: `docs/superpowers/specs/2026-05-08-sp18-reward-shape-hold-attractor-design.md` § DD6 + B-DD13.
## 2026-05-08 — SP17 Phase 3.3: Phase 3 close-out + memory pearl
Phase 3.3 finalises the SP17 dueling-Q diagnostic chain: