feat(dqn-v2): Plan 4 Task 2b — extend layout fingerprint to cover param-tensor layout

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) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-25 11:44:07 +02:00
parent f00c056b49
commit c55c24699a
2 changed files with 56 additions and 5 deletions

View File

@@ -578,17 +578,28 @@ const fn fnv1a_64(bytes: &[u8]) -> u64 {
}
/// Source bytes for the layout fingerprint. Canonical format:
/// `b"<slot_name>=<index>;<slot_name>=<index>;...;ISV_TOTAL_DIM=<N>"`.
/// `b"<slot_name>=<index>;<slot_name>=<index>;...;ISV_TOTAL_DIM=<N>;\
/// PARAM_<TENSOR>=<idx>;...;PARAM_TOTAL_TENSORS=<M>"`.
///
/// 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_<N>_<PURPOSE>` 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_<NAME>=<idx>`
/// 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.

View File

@@ -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_<NAME>=<idx>` 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 |