Commit Graph

11 Commits

Author SHA1 Message Date
jgrusewski
8bc6f1ccd3 fix(dqn): mag_concat_qdir SH2+b0 vs SH2+3 off-by-one — buffer + weight migration
compute-sanitizer pinpointed mag_concat_qdir at experience_kernels.cu:3590
writing 260 floats/state (SH2 + b0_size where b0=4) into a buffer
allocated for 259 floats/state (SH2 + 3, legacy 3-direction layout).
Off-by-one corrupted the next row's first column on every write and
overran past the buffer end on the final row, surfacing as
CUDA_ERROR_ILLEGAL_ADDRESS in downstream kernels (denoise_bias_grad_p1,
cublasLt h_v matmul) on L40S production batch sizes.

The `+3` constant was overloaded:
- direction-conditioned (mag_concat, w_b1fc, w_gate_1) — incorrectly
  hardcoded SH2+3 instead of SH2+branch_0_size when the kernel migrated
  to 4-direction (S/H/L/F).
- OFI-conditioned (ord_concat, urg_concat, w_b2fc, w_b3fc, w_gate_2,
  w_gate_3) — correctly SH2+3 for 3 OFI features per branch
  (concat_ofi_features).

Migrated all direction-conditioned consumers in lockstep
(feedback_no_partial_refactor):

- gpu_dqn_trainer.rs: w_b1fc, w_gate_1 use shared_h2+branch_0_size
- gpu_dqn_trainer.rs: split mag_concat_dim (SH2+b0) from
  ofi_concat_dim (SH2+3) for buffer alloc
- gpu_dqn_trainer.rs: accumulate_d_h_s2_from_concat takes src_stride
  param so mag callers pass SH2+b0, ord/urg callers pass SH2+3
- batched_forward.rs: split mag_concat_dim (SH2+b0) from ofi_concat_dim
  (SH2+3); strided_scatter dst_stride and fc_k now diverge between mag
  (d==1) and ord/urg (d==2,3); add separate (SH2+3) GEMM cache shape
- batched_backward.rs: d==1 (magnitude) dX/dW dims use SH2+b0;
  d==2/3 (order/urgency) keep SH2+3; add separate (SH2+3) GEMM cache
  shape for OFI branches
- gradient_budget.rs: smoke test now allocates b1 with SH2+b0
  and b2/b3 with SH2+3 (was buggy SH2+3 for all three)
- value_decoder.rs: doc updated
- docs/dqn-named-dims.md: new "Branch FC input strides" section
  documenting the direction- vs OFI-conditioning invariant

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:19:41 +02:00
jgrusewski
3e5e3ff206 feat(dqn-v2): D.6 plan_isv[6] = remaining_fraction
Adds 7th plan_isv dimension: PLAN_ISV_REMAINING_FRACTION = max(0, min(1,
(plan_target_bars - hold_time) / plan_target_bars)) when plan active, else
0. Exposes temporal pressure to the policy.

State vector grows 104 → 112 (105 + 7 padding for 8-alignment).
SL_PORTFOLIO_PLAN_DIM 6 → 7. SL_PADDING_DIM 0 → 7.

Both training (experience_env_step) and val (backtest_plan_state_isv) write
the new slot identically — preserves train/val state-distribution parity.

All hardcoded stride-6 references in backtest_plan_kernel.cu replaced with
SL_PORTFOLIO_PLAN_DIM. plan_isv_buf allocation updated to n_windows * 7.
Stale offset comments ([86..92)) corrected to [98..105) across all files.

No behavioural change to existing dimensions. New signal is additive.

Plan 2 Task 6A. Spec §4.D.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 20:36:46 +02:00
jgrusewski
d6e8131d66 refactor(dqn-v2): Task 4 gap-fix — missed sites + Rust mirror
Follow-up to Plan 1 Task 4 sub-commits 4A-4F. Addresses 3 issues
surfaced by code review:

1. experience_kernels.cu:1148-1152 — 4 raw literals missed by Task 4A/4E
   sed sweep (the block uses portfolio_states[ps_base_plan + N] syntax
   rather than ps[N], so sed targeting \bps\[ didn't match).
   Fixes: ps_base_plan + 23 -> PS_PLAN_TARGET_BARS, + 0 -> PS_POSITION,
          dir_idx = 2 -> DIR_LONG, dir_idx = 0 -> DIR_SHORT.

2. experience_kernels.cu:1194 — flat_idx = 3 replaced with DIR_FLAT.

3. crates/ml-core/src/state_layout.rs — Rust mirror added for every
   Task 4 constant (PS_*, PLAN_ISV_*, PLAN_PARAM_*, BRANCH_*, DIR_*,
   MAG_*) matching cuh byte-for-byte. Closes the half-applied Invariant
   8 gap for the Rust side.

No behavioural change. Pure refactor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
7ace16de2f docs(dqn): update dqn-named-dims.md with 4F commit SHA
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
a7c4bc9a90 refactor(dqn): Plan 1 Task 4F — MAG_* magnitude sub-index named constants (Invariant 8)
Define MAG_QUARTER=0, MAG_HALF=1, MAG_FULL=2, NUM_MAGNITUDES=3 in
state_layout.cuh. Migrate the one unambiguous semantic comparison in
trade_physics.cuh (compute_target_position_4branch magnitude scaling).
Arithmetic operations on mag_idx (mag_idx±1, 2-mag_idx, mag_idx<2) are
runtime values, not semantic comparisons, and are not migrated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
2ecf36b94c refactor(dqn): Plan 1 Task 4E — DIR_* direction sub-index named constants (Invariant 8)
Define DIR_SHORT=0, DIR_HOLD=1, DIR_LONG=2, DIR_FLAT=3, NUM_DIRECTIONS=4 in
state_layout.cuh. Migrate all literal dir_idx/raw_dir comparisons to named
constants across experience_kernels.cu (15 sites), trade_physics.cuh (3 sites),
and backtest_metrics_kernel.cu (2 sites). Raw integer comparisons (== 0/1/2/3)
eliminated from all direction-branch consumers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
fc2d65c1a3 refactor(dqn-v2): Invariant 8 — named constants for branch indices
Add BRANCH_DIR/BRANCH_MAG/BRANCH_ORD/BRANCH_URG/NUM_BRANCHES to
state_layout.cuh. Migrate the 4 clear literal branch-index accesses
in branch_grad_balance_kernel.cu (branch_norms_dev[0..3] in
grad_balance_isv_update).

Other branch-keyed arrays (branch_starts, branch_lens, branch_norms,
branch_scales) use the runtime `branch = blockIdx.y` variable or loop
counter — no raw literal index, so no migration needed. Rust call sites
use struct fields (branch_0_size etc.) or loop vars — not literals.

No behavioural change; pure refactor.

Plan 1 Task 4D. Spec §3 Invariant 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
a5a67ad19a refactor(dqn-v2): Invariant 8 — named constants for plan_params[0..6)
Add PLAN_PARAM_* constants to state_layout.cuh and replace raw
plan_params/pp slot accesses in experience_kernels.cu and
backtest_plan_kernel.cu.

Sites migrated: pp[0..5] in both files (12 sites), plan_params_ptr
indexed accesses at slots 0, 1, 4 in experience_kernels.cu (4 sites),
plan_params[w*6+4] in backtest_plan_kernel.cu (1 site). Loop variable
pp[p] in noisy-plan path left as-is (p is a runtime loop counter, not
a literal slot index).

No behavioural change; pure refactor.

Plan 1 Task 4C. Spec §3 Invariant 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
f36b1bde7a refactor(dqn-v2): Invariant 8 — named constants for plan_isv[0..6)
Add PLAN_ISV_* constants to state_layout.cuh and replace raw
plan_isv[N] and pisv[N] accesses in experience_kernels.cu and
backtest_plan_kernel.cu. backtest_plan_kernel.cu gains an
#include "state_layout.cuh" so the constants are visible.

6 code sites migrated (plan_isv[0..5] in experience_kernels.cu),
plus 6 pisv[N] local-array accesses in backtest_plan_kernel.cu
(same semantic slots).

No behavioural change; pure refactor.

Plan 1 Task 4B. Spec §3 Invariant 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
7a2adeb374 refactor(dqn-v2): Invariant 8 — named constants for portfolio state ps[0..PS_STRIDE=38)
Replace raw ps[N] access across all CUDA kernels with PS_* named
constants defined in state_layout.cuh. 32 constants total covering
the full 38-slot portfolio state: position/cash/value, DSR stats,
Kelly stats, plan fields, and OFI scratch range.

Notable deviations from pre-written plan mapping: the plan's
PS_VALUE/PS_POSITION/PS_CASH values (0,1,2) had the wrong semantics.
Code wins (feedback_trust_code_not_docs): ps[0]=position, ps[1]=cash,
ps[2]=portfolio_value. All 148 raw ps[digit] accesses in
experience_kernels.cu and trade_stats_kernel.cu migrated. In-comment
range references (e.g. "ps[30..37]") left as documentation.

trade_stats_kernel.cu: migrated base+14 offset to PS_KELLY_WIN_COUNT.
docs/dqn-named-dims.md: PS_* table corrected to match actual code layout.

No behavioural change; pure refactor.

Plan 1 Task 4A. Spec §3 Invariant 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:37:00 +02:00
jgrusewski
06989cfdf9 infra(dqn-v2): audit doc scaffolding + pre-commit enforcement
Plan 1 Task 1. Creates the five audit docs plus config/metric-bands.toml
that track Invariants 2, 7, 8 per the DQN v2 spec, and extends the
pre-commit hook with two checks:

  - component-adding commits must touch an audit doc (Invariant 7)
  - added code may not contain TODO/FIXME/XXX/HACK/TBD/unimplemented!/
    todo! markers (Invariant 9)

Tests: manually verified by staging a TODO-marked file; commit
rejected with the correct error message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:25:27 +02:00