From c55c24699ac3eddde2ddf06d8f8e4108da7c71f6 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sat, 25 Apr 2026 11:44:07 +0200 Subject: [PATCH] =?UTF-8?q?feat(dqn-v2):=20Plan=204=20Task=202b=20?= =?UTF-8?q?=E2=80=94=20extend=20layout=20fingerprint=20to=20cover=20param-?= =?UTF-8?q?tensor=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prerequisite for Plan 4 Task 2c (GRN ADOPT). The current layout_fingerprint_seed() only covers ISV slot names + indices; param-tensor layout shifts (which GRN insertion will cause) pass silently through checkpoint load. Extends the seed string to include all 86 param-tensor positions by canonical name. Any structural reshuffle (insert/delete/rename a tensor) now triggers a different fingerprint and fail-fast at checkpoint load. Pragmatic scope (Option A): tensor names + positions, not sizes. Sizes depend on runtime config (shared_h1, shared_h2, etc.) and can't be embedded in a const fn. Size mismatches between checkpoint and current binary are caught by safetensors deserialization separately. Task 2c's GRN insertion is structural (new tensor names at new positions) — Option A suffices. This commit IS a checkpoint break: every existing checkpoint's fingerprint matches the old seed and fails load. Behavior change zero; cold-start smoke passes at baseline Sharpe range (fold-2 best Sharpe = 96.65). New fingerprint value: 0xa504d3c2f275b8af. Pearl-aligned: complete fingerprint coverage for what it claims to protect. Partial coverage was worse than no coverage because it implied safety where there wasn't. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ml/src/cuda_pipeline/gpu_dqn_trainer.rs | 59 +++++++++++++++++-- docs/dqn-wire-up-audit.md | 2 + 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs b/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs index e8e18fff1..1b931ba80 100644 --- a/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs +++ b/crates/ml/src/cuda_pipeline/gpu_dqn_trainer.rs @@ -578,17 +578,28 @@ const fn fnv1a_64(bytes: &[u8]) -> u64 { } /// Source bytes for the layout fingerprint. Canonical format: -/// `b"=;=;...;ISV_TOTAL_DIM="`. +/// `b"=;=;...;ISV_TOTAL_DIM=;\ +/// PARAM_=;...;PARAM_TOTAL_TENSORS="`. /// -/// When adding/removing a slot, add/remove its entry here in the SAME commit -/// that changes the constant list. The fingerprint recomputes automatically. -/// Order matches the constant declaration order in this module. +/// When adding/removing a slot OR a param tensor, add/remove its entry here in +/// the SAME commit that changes the underlying list. The fingerprint +/// recomputes automatically. Order matches the constant/tensor declaration +/// order in this module. /// /// Slots [0..12) have no named `pub const` (they are written directly via /// literal indices in `isv_signal_update`). They are covered here by /// `SLOT__` entries derived from the `ISV_TOTAL_DIM` docstring /// and `experience_kernels.cu` write-site comments. Any renumber of these /// slots changes the seed and invalidates the fingerprint. +/// +/// Param-tensor section (Plan 4 Task 2b): the 86 entries `PARAM_=` +/// mirror `compute_param_sizes()` exactly. Names match the in-code comments +/// at each tensor index. Sizes are runtime-config-dependent (`shared_h1` etc.) +/// and intentionally NOT encoded — the const-fn fingerprint covers +/// **structural layout** (tensor names + positions). Size mismatches between +/// checkpoint and current binary are detected separately by safetensors +/// deserialization. Any structural reshuffle (insert/delete/reorder/rename a +/// tensor) changes the seed and triggers fail-fast at checkpoint load. const fn layout_fingerprint_seed() -> &'static [u8] { b"SLOT_0_Q_DRIFT=0;\ SLOT_1_GRAD_NORM_EMA=1;\ @@ -626,7 +637,45 @@ const fn layout_fingerprint_seed() -> &'static [u8] { VSN_MAG_EMA=87;VSN_DIR_EMA=88;MAMBA2_RETENTION_EMA=89;\ TARGET_DRIFT_MAG_EMA=92;TARGET_DRIFT_DIR_EMA=93;\ ISV_LAYOUT_FINGERPRINT_LO=94;ISV_LAYOUT_FINGERPRINT_HI=95;\ - ISV_TOTAL_DIM=96" + ISV_TOTAL_DIM=96;\ + PARAM_W_S1=0;PARAM_B_S1=1;PARAM_W_S2=2;PARAM_B_S2=3;\ + PARAM_W_V1=4;PARAM_B_V1=5;PARAM_W_V2=6;PARAM_B_V2=7;\ + PARAM_W_B0FC=8;PARAM_B_B0FC=9;PARAM_W_B0OUT=10;PARAM_B_B0OUT=11;\ + PARAM_W_B1FC=12;PARAM_B_B1FC=13;PARAM_W_B1OUT=14;PARAM_B_B1OUT=15;\ + PARAM_W_B2FC=16;PARAM_B_B2FC=17;PARAM_W_B2OUT=18;PARAM_B_B2OUT=19;\ + PARAM_W_B3FC=20;PARAM_B_B3FC=21;PARAM_W_B3OUT=22;PARAM_B_B3OUT=23;\ + PARAM_W_BN=24;PARAM_B_BN=25;\ + PARAM_W_VSN1_0=26;PARAM_W_VSN2_0=27;\ + PARAM_W_VSN1_1=28;PARAM_W_VSN2_1=29;\ + PARAM_W_VSN1_2=30;PARAM_W_VSN2_2=31;\ + PARAM_W_VSN1_3=32;PARAM_W_VSN2_3=33;\ + PARAM_W_GATE_0=34;PARAM_B_GATE_0=35;\ + PARAM_W_GATE_1=36;PARAM_B_GATE_1=37;\ + PARAM_W_GATE_2=38;PARAM_B_GATE_2=39;\ + PARAM_W_GATE_3=40;PARAM_B_GATE_3=41;\ + PARAM_KAN_COEFF_0=42;PARAM_KAN_RESID_0=43;\ + PARAM_KAN_COEFF_1=44;PARAM_KAN_RESID_1=45;\ + PARAM_KAN_COEFF_2=46;PARAM_KAN_RESID_2=47;\ + PARAM_KAN_COEFF_3=48;PARAM_KAN_RESID_3=49;\ + PARAM_W_REGIME=50;PARAM_B_REGIME=51;\ + PARAM_SPACING_RAW_0=52;PARAM_SPACING_RAW_1=53;\ + PARAM_SPACING_RAW_2=54;PARAM_SPACING_RAW_3=55;\ + PARAM_W_V1_5BAR=56;PARAM_B_V1_5BAR=57;\ + PARAM_W_V2_5BAR=58;PARAM_B_V2_5BAR=59;\ + PARAM_W_V1_20BAR=60;PARAM_B_V1_20BAR=61;\ + PARAM_W_V2_20BAR=62;PARAM_B_V2_20BAR=63;\ + PARAM_W_RISK_FC=64;PARAM_B_RISK_FC=65;\ + PARAM_W_RISK_OUT=66;PARAM_B_RISK_OUT=67;\ + PARAM_W_ISV_FC1=68;PARAM_B_ISV_FC1=69;\ + PARAM_W_ISV_FC2=70;PARAM_B_ISV_FC2=71;\ + PARAM_W_ISV_GATE=72;PARAM_B_ISV_GATE=73;\ + PARAM_W_ISV_GAMMA=74;PARAM_B_ISV_GAMMA=75;\ + PARAM_W_CONF_FC=76;PARAM_B_CONF_FC=77;\ + PARAM_W_FEATURE_GATE=78;PARAM_B_FEATURE_GATE=79;\ + PARAM_W_TEMPORAL_ROUTE=80;PARAM_B_TEMPORAL_ROUTE=81;\ + PARAM_W_PLAN_FC=82;PARAM_B_PLAN_FC=83;\ + PARAM_W_PLAN_OUT=84;PARAM_B_PLAN_OUT=85;\ + PARAM_TOTAL_TENSORS=86" } /// Compile-time layout fingerprint. Burned into the binary at build time. diff --git a/docs/dqn-wire-up-audit.md b/docs/dqn-wire-up-audit.md index c3bbdd3a1..8216942f7 100644 --- a/docs/dqn-wire-up-audit.md +++ b/docs/dqn-wire-up-audit.md @@ -277,6 +277,8 @@ Plan 4 Task 5 Mode A E.5 (2026-04-24): `attention_focus_ema_kernel.cu` + `Attent Plan 4 Task 4 E.4 (2026-04-24): `state_encoder.rs` + `value_decoder.rs` Rust API split. PURE Rust API refactor — no kernel changes, no parameter changes, no checkpoint break, no new ISV slot. New types: `StateEncoder` (wraps trunk encoder `h_s1` + `h_s2`), `ValueDecoder` (per-branch FC + adv-logits, one instance per `Branch::{Dir,Mag,Ord,Urg}`), `EncoderOutput`, `BranchDecoderOutput` (carries `q_per_action_dev_ptr` + Plan 2 D.3 `v_short_dev_ptr` / `v_long_dev_ptr` pass-through fields). `BatchedForward` gains `encoder_forward_only(...)` and `decoder_forward_only(branch_idx, ...)` helpers, both lossless extractions of the existing dispatch sequence in `forward_online_raw`. The monolithic `forward_online_raw` stays callable and now routes through `encoder_forward_only` internally for the trunk portion (multi-stream branch fork/join unchanged). The new types are ADDITIVE attachment points for Plan 4 Task 1 (Full VSN, pre-encoder), Task 3 (multi-Q IQN, decoder), and Task 6 (auxiliary heads, decoder peer). 2 new Wired rows. +Plan 4 Task 2b (2026-04-24): `layout_fingerprint_seed()` extended to cover **param-tensor structural layout** in addition to the existing ISV-slot section. 86 new entries `PARAM_=` plus `PARAM_TOTAL_TENSORS=86` appended to the seed string, mirroring `compute_param_sizes()` order one-for-one. Names match the in-code comments at each tensor index (`PARAM_W_S1=0`, `PARAM_B_S1=1`, … `PARAM_W_PLAN_OUT=84`, `PARAM_B_PLAN_OUT=85`). Pragmatic Option A scope: tensor names + positions only, NOT runtime sizes — `shared_h1`/`shared_h2`/`adv_h`/`value_h`/`num_atoms`/`bottleneck_dim`/`market_dim` are runtime config and can't be embedded in a `const fn`. Size mismatches between checkpoint and current binary are caught separately by safetensors deserialization. After this commit, ANY structural reshuffle (insert/delete/reorder/rename a tensor) changes `LAYOUT_FINGERPRINT_CURRENT` and triggers fail-fast at checkpoint load. Prerequisite for Plan 4 Task 2c (GRN ADOPT) — without 2b, GRN's tensor insertion would pass silently through checkpoint load and corrupt downstream state. ISV-slot portion of the seed unchanged. New fingerprint value: `0xa504d3c2f275b8af`. Behavior change zero; this commit IS a checkpoint break by intent. No new module / kernel / ISV slot — pure contract-coverage extension. + | Classification | Count | |---|---| | Wired | 88 |