Commit Graph

3046 Commits

Author SHA1 Message Date
jgrusewski
e0dced887f fix(test): resolve test_data_dir from CI PVC layout (ohlcv/ES.FUT)
CI PVC structure is /data/test-data/ohlcv/ES.FUT, local is
test_data/ES.FUT. test_data_dir() now searches both layouts
and checks both FOXHUNT_TEST_DATA and TEST_DATA_DIR env vars.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 09:36:07 +01:00
jgrusewski
472dffd0f3 fix(cuda): shmem tile overflow + cudarc event tracking → 2 CUDA errors
Root cause 1 — CUDA_ERROR_ILLEGAL_ADDRESS:
shmem_max_in_dim only included trunk dims (state_dim, shared_h1,
shared_h2) but not head dims (value_h, adv_h). BF16 weight tile
for branch output overflowed shared memory on RTX 3050 (48KB).

Root cause 2 — CUDA_ERROR_INVALID_VALUE on EMA kernel:
cudarc 0.17's automatic event tracking records read/write events on
CudaSlice buffers. During CUDA Graph capture (events disabled) then
replay (events re-enabled), stale write events from CudaSlice Drops
poison the context error_state. Next bind_to_thread() propagates it.
Fix: disable_event_tracking() at GpuDqnTrainer construction —
single-owner forked stream, all sync points are explicit.

Also:
- Remove all #[ignore] from smoke tests, use real ES.FUT .dbn data
- Validate DBN schema at file level (skip non-OHLCV)
- Organize test_data/ into per-symbol subdirectories
- Fix pre-existing gpu_kernel_parity_test + evaluate_baseline errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 09:18:49 +01:00
jgrusewski
492fdc025e fix(data): skip non-OHLCV record types in DBN loader instead of hard error
MBP-10 .dbn files mixed into test_data/ caused OHLCV loader to crash
on unknown RType 0x42. Now silently skips non-OHLCV records.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:38:38 +01:00
jgrusewski
ad28482a93 fix(cuda): shmem tile overflow → CUDA_ERROR_ILLEGAL_ADDRESS on RTX 3050
Root cause: shmem_max_in_dim only included trunk dims (state_dim,
shared_h1, shared_h2) but not head dims (value_h, adv_h). When
hidden_dim_base=32 made the trunk narrow while heads stayed at 128,
the BF16 weight tile for branch output (255×128=32640 BF16 elements)
overflowed the shared memory region (12288 BF16 elements). On H100
the overflow landed in unused-but-mapped hardware shmem (silent
corruption). On RTX 3050 (48KB physical shmem) it hit unmapped
memory → CUDA_ERROR_ILLEGAL_ADDRESS.

Changes:
- gpu_dqn_trainer.rs: shmem_max_in_dim includes value_h/adv_h
- Remove all #[ignore] from smoke tests (feature_coverage,
  training_stability, gpu_residency)
- Smoke tests use real .dbn data from test_data/ (hard error if missing)
- Remove synthetic_data() fallback — no fake data in tests
- GPU-direct DtoD training path (train_step_gpu, FusedTrainScalars)
- GPU-native PER priority update kernel (zero CPU readback)
- IQN dual-head integration (gpu_iqn_head.rs)
- BF16 dtype fixes across 6 model adapters
- Hyperopt 30D→31D (iqn_lambda)
- portfolio_transformer: unconditional BF16 (remove dead CPU branches)
- liquid/adapter: all tests use Cuda(0) directly
- Fix pre-existing gpu_kernel_parity_test.rs (stale args)
- Fix pre-existing evaluate_baseline.rs (removed fields)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:34:51 +01:00
jgrusewski
12b9eb2436 refactor(cuda): remove dead non-branching code paths
- Delete BranchingWeightSet::zeros() — branching always enabled,
  placeholder buffers never needed
- gpu_experience_collector: remove use_branching field/param, always
  extract branching weights, always use branching-aware sync
- training_loop: remove use_branching guard from network selection
- gpu_weights test: fix dtype assertion F32→BF16

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 23:08:55 +01:00
jgrusewski
2ea96c4c00 fix(cuda): restore graph capture, fix SCRATCH1_DIM OOB, fix BF16 grad norm
- CUDA training kernel: SCRATCH1_DIM = max(SHARED_H1, VALUE_H + ADV_H)
  fixes register array OOB in dqn_forward_loss_kernel distributional path
- gpu_dqn_trainer: restore CUDA graph capture/replay (was bypassed for
  debug), remove 4 debug stream.synchronize() that serialized GPU pipeline
- gpu_dqn_trainer: disable/enable cudarc event tracking around graph
  capture to prevent cross-stream event references from invalidating capture
- gpu_dqn_trainer: opt-in to >48KB dynamic shared memory when needed
- fused_training + gpu_backtest_evaluator: fork() dedicated stream for
  graph capture (legacy stream 0 does not support begin_capture)
- gpu_weights: update struct comments from scalar to distributional C51
  shapes, keep BranchingWeightSet::zeros() scalar-sized for experience
  collector placeholder buffers
- 5 supervised adapters (tgnn/tlob/kan/xlstm/diffusion): cast BF16 grad
  norm tensors to F32 before to_scalar::<f32>() extraction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 22:45:08 +01:00
jgrusewski
450c23a6d0 refactor(cuda): eliminate all CPU fallbacks — CUDA mandatory across ML stack
- Remove ALL #[cfg(feature = "cuda")] guards (~400+ occurrences)
- Remove ALL #[cfg_attr(not(feature = "cuda"), ignore)] test annotations (~250)
- Make cuda default feature in 9 ML crates (ml, ml-core, ml-dqn, ml-ppo, etc.)
- Convert nvrtc JIT compilation to precompiled nvcc (searchsorted, prefix_sum)
- Move compile_ptx_for_device() to ml-core for shared access
- Delete dead CPU code: multi_step.rs, self_supervised_pretraining.rs,
  training_guard_gpu_tests.rs, CPU PER buffer paths, CPU Q-diagnostics
- Replace unwrap_or(Device::Cpu) with hard errors everywhere
- Remove dead is_cuda() else branches in DQN/PPO/hyperopt trainers
- Change config defaults from "cpu" to "cuda" (rainbow, tlob, pipeline)
- Port IQL value network to GPU kernel (5 CUDA entry points)
- Port HER goal relabeling to GPU kernel (warp-per-sample)
- Wire DSR GPU-to-CPU sync in training loop
- cfg!(feature = "cuda") → true in inference_validator

Zero warnings, zero errors across entire workspace.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:01:28 +01:00
jgrusewski
979f135271 fix(cuda): add BF16 input casts to forward methods after mixed_precision removal
After removing ensure_training_dtype(), forward methods that receive F32
inputs from tests/callers now fail with dtype mismatch against BF16 weights.
Add to_dtype(BF16) at forward entry of xLSTM (slstm, mlstm, block, network),
CfC cell, and diffusion time embedding. Fix quantization to accept BF16
tensors by casting to F32 before INT8 conversion. Update guard to catch
#[cfg(not(feature = "cuda"))] dead code. Bump DQN emergency_safe_defaults
replay_buffer_capacity from 1000 to 2048 (GPU PER floor = 1024).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:46:43 +01:00
jgrusewski
c5961cb766 refactor(cuda): remove all #[cfg(not(feature = "cuda"))] dead CPU paths
Delete every CPU fallback block across 14 files (-286 lines):
- dqn.rs: CPU replay buffer, tensor construction, PER fallback, gradient paths
- hyperopt/adapters/ppo.rs: CPU curiosity modules, trajectory generation
- hyperopt/adapters/dqn.rs: CPU backtest fallback, sync no-op
- trainers/ppo.rs: CPU training error stub
- l2_cache.rs: CPU stub functions (gate callers behind cuda too)
- replay_buffer_type.rs: CPU is_gpu_prioritized fallback
- validation/harness.rs: CPU regime breakdown fallback
- build.rs: cpu_only_build cfg (never referenced)
- evaluate_baseline.rs: CPU gpu_handled fallback
- testing/integration/gpu: CPU test stubs

Zero #[cfg(not(feature = "cuda"))] remains in the codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:26:41 +01:00
jgrusewski
d95e205d4b refactor(ml): delete mixed_precision module — BF16 unconditional on CUDA
Eliminate the entire mixed_precision runtime indirection layer:
- Delete crates/ml-core/src/mixed_precision.rs (training_dtype, ensure_training_dtype, align_dim_for_tensor_cores)
- Inline ~100 call sites across 130 files to constants:
  training_dtype(&device) → candle_core::DType::BF16
  ensure_training_dtype(x) → x.to_dtype(candle_core::DType::BF16)
  align_dim_for_tensor_cores(x, &device) → (x + 7) & !7
- Remove re-exports from ml-dqn, ml-supervised, ml lib.rs
- Clean config/toml/json/shell references

No CPU/Metal training path exists — BF16 is the only dtype.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:11:48 +01:00
jgrusewski
cd54a6f27d fix(cuda): resolve 2h H100 test timeout — AutoReplaySizer inflation + CPU PER fallback chain
AutoReplaySizer inflated smoke test buffer_size=500 to 10M on H100 (75GB VRAM),
causing GPU PER empty-sample failures and multi-hour hangs. Root cause: the sizer's
100K minimum was always above the test buffer size, so the guard never triggered.

Fixes:
- constructor.rs: skip auto-sizing when buffer_size < 100K (sizer's own minimum)
- config.rs: insert_batch_tensors falls back to CPU PER (download + add_batch)
  when GPU PER unavailable, instead of hard error
- train_step.rs: skip fused CUDA Graph init when GPU PER not active (stream
  capture can't include CPU→GPU transfers from CPU PER sampling)
- dqn.rs: allow CPU tensor construction path on CUDA when GPU PER falls back;
  remove hard errors in PER priority update (2 locations)
- metrics.rs: fix portfolio tensor shape (broadcast_left→expand for 2D concat);
  add CPU PER fallback for Q-value statistics sampling
- agent.rs, entropy_regularization.rs: GPU-native Gumbel-max via Tensor::rand
  (eliminates per-call CPU Vec allocation + GPU upload)
- smoke test helpers: defense-in-depth replay_buffer_vram_fraction = 0.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 14:11:13 +01:00
jgrusewski
1fef9c401c fix(cuda): force decimal point in V_MIN/V_MAX defines to avoid UDL parse error
nvcc (C++11 mode) parses `25f` as an attempt to use user-defined literal
suffix `f` instead of the standard float suffix. When V_MIN/V_MAX are
injected as integer-formatted values (e.g., `-25f` from Rust's Display
trait on f32), nvcc fails with "user-defined literal operator not found".

Fix: use `{v_min:.1}f` format to guarantee a decimal point (`-25.0f`),
which is unambiguously a float literal in all C++ standards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:39:42 +01:00
jgrusewski
a2ef8f0871 fix(cuda): guard DQN-specific q_forward_dueling_warp_shmem behind #if defined()
Non-DQN kernels (curiosity, PPO, epsilon-greedy, backtest-PPO) include
common_device_functions.cuh but don't define SHARED_H1/SHARED_H2/VALUE_H/ADV_H.
The unguarded q_forward_dueling_warp_shmem() references these constants,
causing nvcc compilation failures (undefined identifiers + cascading
"user-defined literal operator not found" errors).

Wraps the function in #if defined(SHARED_H1) && defined(SHARED_H2) &&
defined(VALUE_H) && defined(ADV_H) ... #endif so it's only compiled
when the DQN architecture constants are injected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 09:59:32 +01:00
jgrusewski
8e0bcbcad3 fix(cuda): forward-declare warp_reduce_sum_all before BF16 matvec
The BF16 matvec helpers (warp_matvec_bf16_shmem, warp_matvec_bf16_broadcast_shmem)
call warp_reduce_sum_all which is defined later in the header. nvcc on H100
rejects this without a forward declaration — broke experience kernel compilation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 09:38:53 +01:00
jgrusewski
2357337bbd fix(infra): move Argo logs to dedicated argo-logs bucket
Argo artifact logs were stored in foxhunt-training-results which is
meant for model checkpoints. Separate bucket makes logs findable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 09:33:11 +01:00
jgrusewski
c84c51434e fix(tests): add missing TradingState import to DQN trainer tests
The test module used `super::*` but TradingState lives in
crate::dqn, not in the trainer module — broke `cargo test --lib`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 09:25:52 +01:00
jgrusewski
216db0301d fix(gpu): eliminate all GPU→CPU roundtrip violations — zero guard findings
Replace .to_vec1()/.to_vec2() bulk downloads with GPU-resident ops:
- PPO/DQN action selection: Gumbel-max trick (categorical on GPU)
- Scalar readbacks: .to_scalar() instead of .to_vec1()[0]
- GPU stats: abs().max(), sqr().sum_all() — single scalar out
- NaN/Inf check: sum_all().to_scalar().is_finite()
- Guard exclusions: inference output boundaries + CPU fallback with GPU path

26 files across ml-ppo, ml-dqn, ml-supervised, ml (ensemble adapters, metrics, data_loading)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 00:19:09 +01:00
jgrusewski
77715209f6 chore: delete dead demo_dqn.rs, update GPU hot-path guard
- Remove ml-dqn/src/demo_dqn.rs (134 lines, unused)
- Guard: add new hot-path patterns, tighten leak detection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:50:54 +01:00
jgrusewski
3ac51679a1 feat(cuda): fused DQN training kernel + trainer split
Replace 7k-line monolithic trainer.rs with modular trainer/ directory:
  action.rs, constructor.rs, metrics.rs, mod.rs, state.rs,
  tests.rs, training_loop.rs, train_step.rs (6048 lines total)

New fused CUDA training pipeline:
  - dqn_training_kernel.cu: single-kernel forward+loss+backward
  - gpu_dqn_trainer.rs: host-side fused training orchestration
  - fused_training.rs: Rust-side fused training integration

Eliminates per-step CPU↔GPU synchronization in DQN training loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:50:29 +01:00
jgrusewski
6b3a00a0ac feat(cuda): pipeline improvements — double buffer, weights, collectors
- common_device_functions.cuh: extended shared header for fused ops
- double_buffer.rs: async double-buffered GPU memory transfers
- gpu_weights.rs: unified weight management for fused training
- gpu_experience_collector.rs: streamlined GPU experience collection
- gpu_ppo_collector.rs: PPO collector GPU path improvements
- gpu_curiosity_trainer.rs + kernel: curiosity training on GPU
- dqn_experience_kernel.cu: experience kernel updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:49:54 +01:00
jgrusewski
0274f63a2f fix(gpu): delete dead CPU fallback code from GPU hot paths
Remove ~850 lines of unreachable CPU fallback code from 3 hot-path files:

- hyperopt/dqn.rs: delete 250-line CPU backtest path (GPU eval mandatory)
- evaluate_baseline.rs: delete CPU PPO eval + non-CUDA fallback (147 lines)
- trainers/ppo.rs: delete 6 dead CPU rollout methods (~370 lines),
  split train() into dispatcher + #[cfg(feature = "cuda")] train_gpu()

All .to_vec1() GPU hot-path guard violations eliminated.
GPU failures are now hard errors, not silent CPU fallbacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:48:12 +01:00
jgrusewski
9d564a829e fix(guard): restore #[cfg(test)] exclusion, keep cfg(not(cuda)) filter
Unit tests need scalar readbacks for assertions — .to_scalar() is not
flagged but .to_vec1() in test modules would generate false positives.
Guard now correctly excludes inline #[cfg(test)] modules while checking
all production code including ensemble adapters.

Full --all scan reveals 31 pre-existing production violations across
ml-dqn, ml-ppo, ml-supervised, and ensemble adapters — separate cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:11:06 +01:00
jgrusewski
39e5dafc62 fix(cuda): harden GPU hot-path guard — exclude tests, remove false-positive patterns
- Guard: exclude #[cfg(test)] modules (tests need scalar readbacks for assertions)
- Guard: exclude #[cfg(not(feature = "cuda"))] guarded expressions (dead code with CUDA)
- Guard: remove Tensor::from_vec/from_slice from leak patterns (CPU→GPU is correct direction)
- Guard: remove .to_scalar from leak patterns (single 4-byte readback, not bulk transfer)
- dqn.rs: rewrite log_q_values() to use GPU tensor ops (min/max/mean/var), eliminate to_vec1
- dqn.rs: rewrite clip monitoring to use GPU tensor ops, individual .to_scalar() readbacks
- ppo.rs: replace stacked .to_vec1() metrics readback with individual .to_scalar() calls
- evaluate_baseline.rs: single-bar DQN action from .to_vec1::<u32>() to .to_scalar::<u32>()
- mod.rs: remove gpu_upload_vec/gpu_upload_slice wrappers (guard no longer flags from_vec)
- Delete dead demo_dqn.rs (zero callers, stub returning mock results)

Remaining: 4 .to_vec1() violations across 3 files — porting to existing CUDA implementations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:04:46 +01:00
jgrusewski
fee3c858ae fix(cuda): move q_forward_dueling_warp_shmem to common header
The backtest_forward_kernel.cu calls q_forward_dueling_warp_shmem but
it was defined in dqn_experience_kernel.cu — a different compilation unit.
Move the function, TILE_LAYER_WARP_CLEAN macro, SHMEM_MIN and DIST_SIZE
to common_device_functions.cuh so both kernels can use them.

Add #ifndef guards to all macros to prevent redefinition warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:56:23 +01:00
jgrusewski
8ea400e599 fix(cuda): fix TMA inline asm syntax for CUDA 12.9 PTX ISA 8.7
The CI toolkit (CUDA 12.9, PTX ISA 8.7) requires:
1. cp.async.bulk needs .mbarrier::complete_tx::bytes completion mechanism
   (mandatory since PTX ISA 8.3 / CUDA 12.3)
2. mbarrier.try_wait.parity.acquire needs .cta scope qualifier between
   .acquire and .shared::cta

Reverts the DISABLE_TMA workaround — TMA now compiles natively to cubin.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:10:10 +01:00
jgrusewski
8c4861fb70 fix(cuda): always define DISABLE_TMA — CI toolkit cannot assemble cp.async.bulk
The CI CUDA toolkit's ptxas fails on TMA instructions (cp.async.bulk)
with "completion_mechanism modifier required". Prepend #define DISABLE_TMA 1
in compile_ptx_for_device() so ALL kernel compilations (experience collector,
backtest evaluator, PPO collector, curiosity trainer, action selector) use
the float4 cooperative load fallback instead of TMA.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:03:52 +01:00
jgrusewski
8c4657a3a4 fix(infra): resolve commit-sha=HEAD to remote branch tip, not local PVC HEAD
When commit-sha defaults to "HEAD", git checkout HEAD is a no-op — it keeps
the PVC's stale checkout. Now resolves HEAD to origin/{branch} after fetch,
ensuring the latest pushed code is always compiled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 14:49:55 +01:00
jgrusewski
76fdd155a1 fix(cuda): compile to native cubin instead of PTX — eliminate driver JIT entirely
nvcc now produces cubin (native SASS) with -cubin -arch=sm_XX instead of
PTX with -ptx -arch=compute_XX. cuModuleLoad() loads SASS directly — zero
driver JIT. TMA instructions (cp.async.bulk on sm_90+) work natively because
nvcc handles them during offline compilation. Removed TMA fallback from
experience collector (double-compile + 15s retry overhead eliminated).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 14:32:53 +01:00
jgrusewski
e807558cd8 fix(infra): remove --initial-capital from train-best step
train_baseline_rl doesn't accept --initial-capital (only hyperopt and
evaluate binaries do). Removing it fixes the exit code 2 in DQN
hyperopt v3 train-best step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 13:50:46 +01:00
jgrusewski
686f180d7b fix(ppo): pure BF16 dtype alignment across all PPO networks and tensor ops
Cast all Tensor::full() / Tensor::from_vec() call sites to training_dtype
instead of defaulting to F32. Fixes dtype mismatch errors (BF16 vs F32)
in PPO training on CUDA:

- tensor_ops: scalar_mul, clamp, normalize match operand dtype
- trajectories: TrajectoryBatch/MiniBatch to_tensors cast to training dtype
- continuous_ppo: ContinuousTrajectoryBatch/MiniBatch to_tensors cast
- adaptive_entropy: cast entropy to F32 for alpha multiplication boundary
- continuous_policy: forward() input cast, Tensor::full scalars match dtype
- flow_policy: sample_base_noise cast to training dtype
- hidden_state_manager: reset tensors use training_dtype
- ensemble/ppo adapter: predict input cast to training dtype
- trainable_adapter: test uses training_dtype instead of hardcoded F32

Verified: 198/198 ml-ppo tests pass, 63/63 ml PPO tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 13:45:22 +01:00
jgrusewski
910f4bdee3 fix(cuda): dim_overrides before common header in backtest kernel, cap n_episodes at 4096
- backtest_forward_kernel: dim_overrides must precede common_device_functions.cuh
  which has #error guards requiring STATE_DIM/MARKET_DIM/PORTFOLIO_DIM to be
  defined before inclusion. Experience collector already had correct ordering.
- Cap MAX_EPISODES from 8192→4096 (diminishing returns above 4096, wastes walltime)
- Cap trainer .min() from 0x8000 (32768) → 4096 to match

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 13:05:43 +01:00
jgrusewski
92f8cba74a fix(infra): add LD_LIBRARY_PATH stubs filter and env vars to compile-and-train template
The ci-builder image has CUDA stub libraries that shadow real NVIDIA
drivers. Without filtering stubs from LD_LIBRARY_PATH, training binaries
report "CUDA GPU required but none available" even on GPU nodes.

Add to hyperopt, train-best, and evaluate steps:
- LD_LIBRARY_PATH stubs filter (grep -v stubs)
- nvidia-smi verification
- RUST_LOG, SQLX_OFFLINE, CUBLAS_WORKSPACE_CONFIG env vars
- PATH includes /workspace/bin (use binary name, not full path)

Matches the existing pattern in training-workflow-template.yaml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:22:55 +01:00
jgrusewski
08e3b97960 fix(ppo): cast state tensors to training dtype in PPO validation adapters
Fix BF16/F32 dtype mismatch in PpoStrategy and PpoLstmStrategy
validation adapters. Tensor::from_vec(Vec<f32>) creates F32 tensors,
but PPO networks use BF16 weights on H100. Cast state_tensor to
training_dtype() at the boundary before passing to network forward.

Fixes 4 ppo-lib failures on H100:
- test_ppo_strategy_train_and_evaluate
- test_ppo_strategy_reset
- test_ppo_lstm_strategy_train_and_evaluate
- test_ppo_lstm_strategy_reset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:19:15 +01:00
jgrusewski
23a122607d feat(infra): Argo log persistence, network policies, lightweight CI images
- Argo workflow archive via PostgreSQL — persistent logs after pod GC
- Allow Argo controller to reach PostgreSQL via network policy
- Allow Argo server to reach MinIO for S3 log archival
- Replace foxhunt-runtime with lightweight images (alpine:3.21, curlimages/curl)
  in orchestration steps: fetch-binary, upload-results, detect-changes, gpu-warmup
- Use ci-builder for training steps (hyperopt, train-best, evaluate) — nvcc required
- Fix --hyperopt-results → --hyperopt-params flag in train-best step
- Remove invalid podGCGracePeriod from Argo Helm values
- Archive RBAC, kustomization updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:00:46 +01:00
jgrusewski
ca4c38d921 fix(tests): CI GPU test stability, walltime reduction, BF16 tolerance
- Reduce CI GPU test datasets 16x for walltime reduction
- Reduce early-stop epochs 50→10, add --test-threads=1
- Serialize all GPU lib tests to prevent cuBLAS init race
- Align state_dim to 16 for BF16 tensor core HMMA dispatch
- BF16 precision tolerance in ml-dqn tests
- Enable branching DQN + tracing subscriber in smoke tests
- Prevent min_replay_size > buffer_size deadlock in early-stop tests
- Prevent AutoReplaySizer from breaking gradient collapse warmup
- Replace racy tokio::spawn checkpoint counter with AtomicUsize
- Set warmup_steps=0 and max_training_steps_per_epoch=300 in early-stop tests
- RealDataLoader respects TEST_DATA_DIR for CI PVC layout
- Add collapse_warmup_capacity to gpu_smoketest DQNConfig
- Drain CUDA context between test binaries
- Detached HEAD checkout prevents local branch corruption
- GPU pipeline tests: fix BF16 dtype and rank-1 squeeze assertions
- OOD input handling tests use use_gpu: true

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 12:00:13 +01:00
jgrusewski
b4178952d4 fix(ml): BF16/F32 boundary alignment, GPU-resident ops across all ML crates
- Cast input to weight dtype in DQN residual, rmsnorm, noisy_layers
- Set use_gpu=true in QNetworkConfig defaults and all config sites
- Resolve BF16 boundary mismatches in attention, curiosity, branching,
  distributional_dueling across ml-dqn
- GPU-resident regime ops with BF16 boundary casts, eliminate .expect() in CUDA paths
- Eliminate all Device::Cpu fallbacks — GPU-only across 10 ML crates
- PPO: cast logits to F32 before softmax, cast batch tensors to training dtype
- Gradient collapse detection for RegimeConditionalDQN
- Wire halt_grad_collapse from CUDA guard kernel to halt training
- Dead neuron detection uses active network VarMap + squeeze factored readback
- Increment gradient_logging_step in GPU PER path
- Gradient collapse warmup guards use original buffer_size
- Cap training steps per epoch + tracing migration
- Replace Tensor::all() with sum_all() for pinned Candle compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 11:59:31 +01:00
jgrusewski
1fae917c22 perf(cuda): H100 kernel optimizations — nvcc pipeline, kernel fusion, GPU-only training
- Migrate from NVRTC JIT to cached nvcc -O3 for all CUDA kernels
- Fuse guard kernels, increase prefetch chunk, eliminate per-step GPU alloc
- H100-specific: fused Adam, warp reductions, shmem tiling, PPO occupancy
- Vectorize gather_states with __ldg() and 4x unroll
- sincosf() Box-Muller + paired Gaussian generation in noisy nets
- Shared-memory tiled branching DQN forward pass for sm_<90
- GPU-resident training guard kernel replacing Candle tensor ops
- Eliminate all to_vec1/to_vec2 CPU roundtrips, DtoD weight copy
- GPU PER mandatory everywhere — kill CPU replay path on CUDA
- Full GPU action masking — eliminate CPU fallback path
- Fix cuBLAS handle sharing via OnceLock (root cause of 49 cascade failures)
- Fix ILLEGAL_ADDRESS: scratch1_dist buffer overflow, stack sizing, curand determinism
- Fix CudaStream lifetime: bind before .context() to extend lifetime
- Keep raw cudarc buffers alive across epochs
- Add gpu-hotpath-guard.sh (37 patterns) and ptx-cache-invalidate.sh

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 11:58:40 +01:00
jgrusewski
76e1010568 docs: add Kanidm SSO + NetBird mesh design spec and implementation plan
Design spec covers OIDC architecture (RS256 JWKS, WebAuthn-first),
7 service integrations, NetworkPolicy, and phased migration strategy.
Implementation plan: 17 tasks across 6 chunks, reviewed 3 rounds
(2 internal + 1 external Gemini 2.5 Pro expert review, all fixes applied).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 19:41:40 +01:00
jgrusewski
8ce29df5cd fix(netpol): fix 3 DOWN Prometheus targets — operator port, reloader ingress, argo label
- Prometheus→operator: egress port 8443→10250 (actual container port)
- Alertmanager ingress: add port 8080 from Prometheus for config-reloader sidecar
- Argo controller metrics service: remove part-of:foxhunt label (already scraped
  via additionalScrapeConfigs with HTTPS; foxhunt-services ServiceMonitor was
  creating duplicate HTTP target → 400)

Result: 25/25 targets UP, 0 DOWN.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:52:07 +01:00
jgrusewski
e4870b17b9 fix: tune log levels across workspace — demote noisy warn to debug/trace
Reduce log noise for non-critical operational paths: connection retries,
expected fallbacks, graceful degradation, and optional feature absence.
Keeps warn/error for genuine failures requiring attention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:35:15 +01:00
jgrusewski
dba50fa3be fix(dashboards): update datasource UIDs and folder annotations for Helm Prometheus
Update all dashboard JSON files to use Helm chart's Prometheus datasource
UID and add Grafana sidecar folder annotations for auto-provisioning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:34:14 +01:00
jgrusewski
f3012611f0 feat(monitoring): migrate to kube-prometheus-stack Helm chart
Replace standalone Prometheus/node-exporter/kube-state-metrics with
kube-prometheus-stack Helm chart. Add ServiceMonitor CRDs, PrometheusRule
CRDs (HFT + broker alerts), comprehensive network policies, and wire
AlertManager to Mattermost via incoming webhook.

- Delete old standalone prometheus.yaml, node-exporter.yaml, kube-state-metrics.yaml
- Add prometheus-stack-values.yaml (Helm values with Scaleway Kapsule tuning)
- Add service-monitors.yaml (foxhunt-services + dcgm-exporter ServiceMonitors)
- Add prometheus-rules-hft.yaml and prometheus-rules-broker.yaml (PrometheusRule CRDs)
- Rewrite prometheus network policy for operator-managed pods (DNS, kube-state-metrics,
  operator, alertmanager sidecar, monitoring namespace for DCGM)
- Add alertmanager network policy (Mattermost egress)
- Upgrade Grafana: AlertManager datasource, unified alerting, fix nodeSelector
- Fix Tempo: tolerations for GPU nodes, resource tuning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:33:46 +01:00
jgrusewski
aabc1d95e5 fix(infra): pin workflow-trigger eventsource to platform pool
The eventsource had no nodeSelector and landed on ci-compile-cpu
(POP2-HC-32C-64G, €0.56/hr), blocking autoscaler from scaling it
to 0. Now pinned to platform pool — ci-compile-cpu will autoscale
down, saving ~€410/mo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 09:26:31 +01:00
jgrusewski
dd43316a66 feat(monitoring): add Scaleway infrastructure cockpit dashboard
- Pure-Python scraper replaces shell+Python hybrid (fixes pushgateway
  RemoteDisconnected crash caused by duplicate volume name labels)
- Scraper dynamically discovers all Scaleway resources via API:
  billing, instances, K8s pools, block volumes, IPs
- 40-panel cockpit dashboard with fully dynamic tables (auto-adapts
  when infra changes — no hardcoded instance/volume names)
- Volume table keyed by UUID (not truncated name) to prevent collisions
- Label sanitization for Prometheus text format safety
- Pushgateway push via PUT + Content-Type: text/plain; version=0.0.4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 03:09:40 +01:00
jgrusewski
1092c931f3 feat(monitoring): add actual Scaleway billing costs, fix Argo counters
- Add scaleway-billing CronJob: hourly scrape of Scaleway Billing API,
  pushes scaleway_billing_total_eur, scaleway_billing_consumption_eur,
  and scaleway_billing_product_eur metrics to pushgateway
- Update Cluster & Costs dashboard with "Actual Costs (Scaleway Billing API)"
  row: Total MTD, Compute, Storage, Network, Registry stats + product
  breakdown bar chart + category pie chart
- Rename existing cost section to "Projected Costs (by node count)"
- Fix Argo Workflows dashboard: use argo_workflows_gauge for
  Succeeded/Failed counts instead of cumulative counters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 02:38:42 +01:00
jgrusewski
ddf697641a feat(monitoring): add per-service and platform dashboards, reorganize folder structure
- 7 application service dashboards (Services folder): API Gateway, Trading
  Service, Backtesting, Data Acquisition, ML Training, Trading Agent, Web Gateway
- 9 platform dashboards (Platform folder): Prometheus, Grafana, Loki & Promtail,
  Tempo, Redis, PostgreSQL, Argo Workflows, QuestDB, Cluster & Costs
- Cluster & Costs dashboard includes Scaleway node cost estimates (€/hr, €/month)
  for platform, GPU (H100), and CI compile nodes
- Reorganized existing dashboards into 7 folders: CI, Infrastructure, Operations,
  Platform, Services, Trading, Training (dropped "Foxhunt" prefix from titles)
- Rewrote import.sh: removed ConfigMap deployment, switched to API-only imports
  with automatic folder creation and per-dashboard folder mapping
- All 24 dashboards deployed via Grafana API (Postgres-backed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 02:30:52 +01:00
jgrusewski
6349e384d2 feat(monitoring): add Training Deep-Dive dashboard with unified Prometheus + Loki
74-panel dashboard for in-depth pipeline monitoring. Select a running pod
to see training curves, GPU health (DCGM), eval metrics, CI/Argo workflows,
container resources, and live logs in one place. Stored in Postgres via API
(no ConfigMap restarts needed).

Sections: Job Overview, CI Pipeline & Argo Workflows, CI Logs, Training
Curves, Trading Performance, Evaluation Metrics, GPU & Hardware, Throughput,
Hyperopt Trials, Container Resources, Live Logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 02:04:24 +01:00
jgrusewski
e5daea44e0 feat(monitoring): add Loki log dashboards for CI and training pipelines
Two new Grafana dashboards powered by Loki:
- CI Pipeline Logs: test gate, clippy, Redis sidecar, build/deploy, errors
- Training Pipeline Logs: epoch/loss, hyperopt trials, GPU/CUDA, walk-forward, data loading

Both use Promtail-extracted labels (level, container, pod) for efficient
stream selection. Collapsible sections keep overview clean while providing
deep drill-down. Variables for pipeline/job type, log level, and text search.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 01:37:54 +01:00
jgrusewski
ddf1082cb5 Revert "fix(ci): retain completed pods 10 min for log access (CPU only)"
This reverts commit 8e6effb7f6.
2026-03-14 01:10:34 +01:00
jgrusewski
8e6effb7f6 fix(ci): retain completed pods 10 min for log access (CPU only)
Add deleteDelayDuration: 600s to podGC on CPU workflow templates and
sensors (ci-pipeline, compile-deploy, build-image). GPU training
workflows keep immediate cleanup to avoid wasting expensive GPU time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 01:10:06 +01:00