Commit Graph

4015 Commits

Author SHA1 Message Date
jgrusewski
a0bd744e5b fix(infra): remove stale DNS outputs, add chat/mail FQDNs
Remove prometheus_fqdn and monitor_fqdn outputs that referenced
deleted DNS records. Add chat_fqdn and mail_fqdn for Mattermost
and Stalwart services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:47:04 +01:00
jgrusewski
7a90bc87d9 fix(dqn): route walk-forward Q-values through branching network
CRITICAL BUG: When use_branching=true, the optimizer trains ONLY the
branching network, but q_values_for_batch() (used by walk-forward
evaluator) was reading from dist_dueling_q_network — which was never
trained. Walk-forward was evaluating random/untrained weights.

Fix: q_values_for_batch() now uses the exposure branch Q-values
[batch, 5] from the trained branching network when use_branching=true.
Also adds device/dtype migration to match forward() contract.

Fixed IQN test that implicitly had use_branching=true (default) with
num_actions=3 — incompatible with 5-action branching exposure head.

1331 tests pass (416 ml-dqn + 915 ml), 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:43:52 +01:00
jgrusewski
2de3def317 feat(dqn): per-branch independent epsilon for factored action diversity
The single global epsilon coin flip caused 90% of actions to use greedy
argmax across ALL 3 branches simultaneously, collapsing to 1 composite
action. Only 6/45 factored actions were used (13.3% diversity).

Fix: Each branch (exposure, order, urgency) now flips its own epsilon
coin independently:
- P(all greedy) = (1-ε)³ ≈ 72.9% at ε=0.10
- P(at least one random) ≈ 27.1% vs previous 10%
- Expected unique actions per epoch: significantly higher

Applied to both select_action() and select_action_with_confidence().
The forward pass is skipped when all 3 branches happen to be random
(0.1% chance), preserving the optimization.

1331 tests pass (416 ml-dqn + 915 ml), 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:12:27 +01:00
jgrusewski
cbf81d293d fix(backtest): align state_dim to 8 in GPU backtest evaluator
The GPU backtest evaluator computed state_dim = feature_dim + 3 = 53
(unaligned), but the model was trained with 56 (8-aligned for H100
tensor cores). This caused matmul shape mismatch [5,53] vs [56,512]
and forced CPU fallback on every walk-forward evaluation.

Fix: align state_dim at construction with (dim + 7) & !7, matching
the training pipeline. The CUDA gather_states kernel already zero-pads
extra positions, so no kernel changes needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:05:57 +01:00
jgrusewski
70f074658f fix(hyperopt): restore best checkpoint for RegimeConditional agent before walk-forward
serialize_model() saves only the trending (primary) head into a single safetensors
blob. The restore code only handled Standard(DQN) and skipped RegimeConditional
with a warning. This caused walk-forward to always evaluate the final epoch model
instead of the best per-epoch Sharpe checkpoint.

Fix: load the checkpoint directly into primary_head_mut() for the RegimeConditional
variant, matching the serialization path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:59:31 +01:00
jgrusewski
cf6e36c8a1 perf(dqn): restore best-epoch checkpoint before walk-forward evaluation
Walk-forward evaluation was using the final epoch model, which may have
overfit. Now loads the best per-epoch Sharpe checkpoint (saved during
training) back into the agent before running the walk-forward backtest.

Trial 0 showed Sharpe +3.30 at epoch 2 vs +1.84 at epoch 8 (final).
The walk-forward should evaluate the peak model, not the final one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:21:28 +01:00
jgrusewski
a074244422 fix(dqn): raise noisy_epsilon_floor from 0.0 to 0.10 to prevent action collapse
NoisyNets provide learned exploration but their noise magnitude shrinks
during training. When Q-value gaps exceed noise (~0.016 vs ~0.01), the
agent converges to a single action (Short100 only). The 10% epsilon
floor guarantees 2% random selection per exposure level across all
action selection paths (select_action, select_action_with_confidence,
get_effective_epsilon).

Updated 6 test assertions and 5 comments to match the new floor.
1331 tests pass (916 ml + 416 ml-dqn), 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:24:45 +01:00
jgrusewski
91e88e3a55 fix(dqn): reset drawdown tracking at epoch boundary to prevent permanent trade lockout
The circuit breaker (>20% drawdown) carried forward across epochs,
permanently locking out all trades once triggered. With compounding
portfolios, early drawdown in one epoch could produce zero rewards
for all subsequent epochs (constant rewards bug).

Fix: reset peak_value (high-water mark) at each epoch start. Capital
still compounds (Bug #15 preserved), but drawdown is measured fresh
per epoch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:50:58 +01:00
jgrusewski
23157e9faa fix(dqn): normalize VaR/CVaR to percentage returns using initial capital
pnl_history stores raw dollar rewards but VaR calculation treated them
as percentage returns, producing nonsensical -500% VaR values. Now
divides by initial_capital before calculating percentiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:06:17 +01:00
jgrusewski
368975c1cd fix(infra): correct Stalwart image name and volume mount paths
Image renamed from stalwartlabs/mail-server to stalwartlabs/stalwart.
Volume mounts updated from /opt/stalwart-mail/ to /opt/stalwart/
to match the actual container filesystem layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:32:36 +01:00
jgrusewski
df772ff985 fix(metrics): reduce training log noise, fix Prometheus scraping for hyperopt pods
- Drawdown circuit breaker: warn! → debug! (per-bar flooding in portfolio_tracker)
- Volatility epsilon adjustment: info! → debug! (per-step noise in dqn/risk)
- Prometheus: expand training-pods scrape regex to include compile-and-train pods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:29:29 +01:00
jgrusewski
ebf7b39288 feat: CI quality gates, notifications, Mattermost & Stalwart deployment
Merge feature/ci-comms-stack:
- Add clippy + cargo test quality gate to CI pipeline
- Clean up dead detect-changes outputs (-205 lines)
- Add onExit notification handlers (Mattermost webhook) to all workflows
- Add auto-compile ConfigMap toggle (disabled by default)
- Deploy Mattermost Team Edition on platform nodes
- Deploy Stalwart mail server (internal-only, Tailnet IMAP/admin)
- Add Mattermost egress to all Argo workflow NetworkPolicies
- Fix sensor nodeSelectors for decommissioned POP2-32C-128G
- Add DNS records for chat.fxhnt.ai and mail.fxhnt.ai

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:24:32 +01:00
jgrusewski
8803648b4a feat(infra): deploy Stalwart mail server (internal-only, Tailnet access)
Add Stalwart all-in-one mail server: SMTP (cluster-internal relay for
Mattermost), IMAP + HTTPS admin via Tailscale proxy. RocksDB storage,
self-signed TLS (stalwart-tls secret). No public MX, no outbound SMTP.
SCW TEM relay noted in NetworkPolicy comments for future use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:22:27 +01:00
jgrusewski
9e8b9422cf feat(infra): deploy Mattermost on platform nodes with CI webhook egress
Add Mattermost Team Edition deployment (PVC, Service, NetworkPolicy),
DNS records (chat.fxhnt.ai, mail.fxhnt.ai), Tailscale nginx proxy
server block with WebSocket upgrade support, and Mattermost egress
rules to all 5 Argo workflow NetworkPolicies for exit handler webhooks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:20:32 +01:00
jgrusewski
7844523591 feat(ci): add auto-compile ConfigMap toggle (disabled by default)
Add auto-compile-config ConfigMap with enabled=false. Document the
manual compile-deploy webhook trigger and toggle pattern in the
ci-pipeline sensor. Auto-compile can be enabled per-push by adding
a second trigger to the sensor or via manual webhook.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:17:52 +01:00
jgrusewski
86b2e9d1d0 feat(ci): add onExit notification handlers for all workflow templates
Add notify-result exit handler to ci-pipeline, compile-and-deploy, and
compile-and-train templates. Posts workflow outcome to Mattermost via
incoming webhook (secret: notification-webhook). Gracefully skips if
webhook URL is placeholder or missing (optional secretKeyRef).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:16:21 +01:00
jgrusewski
c06954f471 feat(ci): add test-gate step + clean up detect-changes dead outputs
Add clippy + cargo test quality gate to CI pipeline DAG. The test-gate
runs on ci-compile-cpu nodes with persistent cargo cache PVC for fast
incremental builds. Also simplifies detect-changes by removing 5 unused
output parameters (service-packages, training-examples, deploy-list,
needs-services, needs-training) and ~170 lines of dead shell logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:12:40 +01:00
jgrusewski
65f29a8167 fix(infra): update sensor nodeSelectors from DEV1-L to platform pool
POP2-32C-128G is decommissioned. Sensor pods (ci-pipeline-trigger,
workflow-trigger) now target the platform node pool.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:07:59 +01:00
jgrusewski
4e1e4e6f26 fix(argo): set fsGroup=0 for workspace PVC write access across steps
Without fsGroup, workspace PVC created by root-running compile step
is not writable by other steps. fsGroup=0 ensures all pods in the
workflow can write to the shared workspace volume.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:52:42 +01:00
jgrusewski
4e4d26b7f8 fix(argo): self-apply NetworkPolicy, delete stale compile-training template
- apply-argo-templates step now also applies argo-workflow-netpol.yaml
  so NetworkPolicy changes auto-deploy on push
- Deleted stale compile-training WorkflowTemplate from cluster
  (superseded by compile-and-train)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:47:28 +01:00
jgrusewski
bf9a739908 fix(ml): suppress unsafe-code warning on startup env::set_var calls
CUBLAS_WORKSPACE_CONFIG and NVIDIA_TF32_OVERRIDE are set once at
startup before any threads or CUDA work begins. The unsafe block is
correct but triggers -W unsafe-code. Adding #[allow(unsafe_code)] at
the call site silences the warning while keeping the safety comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:46:17 +01:00
jgrusewski
ad2a9662ca fix(argo): remove image rebuild steps from compile-and-train/deploy
Image builds are handled by ci-pipeline, not by compile-and-train or
compile-and-deploy. Having them here caused network policy failures
(Kaniko can't reach registry) and securityContext conflicts (Kaniko
needs root). Also removed pod-level securityContext from
compile-and-train since ci-builder needs root for cargo on PVC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:44:46 +01:00
jgrusewski
45addfd35d feat(infra): auto-rebuild Docker images in CI pipelines, add build-image webhook
- Wire build-image endpoint into EventSource + Sensor for manual triggers
- Add rebuild-* DAG tasks to compile-and-deploy and compile-and-train
  templates — Kaniko layer cache makes cached builds ~15-30s
- Fix foxhunt-runtime Dockerfile: rename ubuntu user instead of groupadd
  (GID 1000 already exists in ubuntu:24.04)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:35:55 +01:00
jgrusewski
fbde4bb165 fix(argo): add network policy for compile-and-train workflow
The compile-and-train workflow uses component label 'compile-and-train'
which wasn't covered by existing network policies. Pods were blocked by
default-deny-all from reaching GitLab SSH (git clone) and HTTP (package
upload/download). Combines compile egress (SSH, external HTTPS, DNS) with
training egress (Tempo OTLP, GitLab HTTP).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:30:44 +01:00
jgrusewski
5a456320fb fix(argo): add git safe.directory for PVC ownership mismatch
PVCs may retain ownership from a previous pod UID (e.g. after
ci-builder image rebuild). Git 2.35.2+ refuses to operate without
safe.directory set. Applied to both persistent-checkout templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:26:25 +01:00
jgrusewski
2245e347c9 fix(argo): add git safe.directory for PVC-persisted checkout
The cargo-target PVC retains the source checkout between workflow runs.
When the container UID differs from the PVC owner, git refuses to operate
with "dubious ownership" error. Adding safe.directory resolves this.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:26:11 +01:00
jgrusewski
38178a6602 fix(docker): drop cuDNN from ci-builder base image
No cudnn feature flags remain after 6ba52425 — the devel headers
and libs were dead weight (~1.5 GB).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:24:32 +01:00
jgrusewski
319554b02e fix(dqn): TensorId gradient clipping fallback, 45-action tracking, small-GPU OOM guard
- gradient_utils: Add TensorId-based fallback when Var identity mismatch
  causes 0/N vars to match GradStore (Candle Adam clones Arcs). Fallback
  computes norm AND clips via insert_id. Throttled warning (1st + every
  1000th). 7 unit tests including mismatch-actually-clips.

- monitoring: Track full 45-action factored space (5 exposure × 3 order
  × 3 urgency). Fix validate_rewards false alarm on GPU path where single
  aggregated mean_reward per epoch gives N=1 → std=0.

- trainer: GPU experience collection routes exposure actions through
  route_action() for factored tracking instead of exposure-only counts.
  Applied in both per-step and epoch-summary paths.

- train_baseline_rl: Auto-detect VRAM <8GB → disable GPU replay buffer
  to prevent OOM on RTX 3050 Ti class GPUs.

- smoke_test_real_data: E2E DQN training test with 6 assertions (epoch
  completion, loss decrease, finite losses, Q-value divergence, 45-action
  space, finite gradient norms).

Validated: 1642 tests pass (ml=915, ml-core=311, ml-dqn=416), 0 clippy
warnings, baseline RL trains 10 epochs on CUDA with Sharpe +5.45.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:15:48 +01:00
jgrusewski
6ba52425ea feat(infra): Argo workflow templates, drop cuDNN, GPU hotpath fixes
- Add compile-and-deploy, train-dqn/ppo/supervised WorkflowTemplates
- Add Argo Events (EventSource, Sensor, Service) for webhook triggers
- Add NetworkPolicy for compile-and-deploy pods (MinIO/DNS/API egress)
- Add convenience scripts: argo-compile-deploy.sh, argo-train.sh
- Drop cuDNN feature flags from all 9 ML crates (zero conv ops in codebase)
- Switch training runtime base to nvidia/cuda:12.9.1-runtime (saves ~800MB)
- Delete unused selective_scan.cu (16KB, zero Rust callers)
- Fix GPU hotpath violations in ml-core (NVTX, gradient utils, capabilities)
- Fix clippy warnings in ml-dqn (VarMap backticks, const fn)
- Add DQN GPU smoketest, backtest evaluator signal adapter fixes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:44:03 +01:00
jgrusewski
a334ca288f fix(cuda): fix GPU hotpath guard violations + dynamic shmem in backtest forward kernel
Move // gpu-ok: annotations to same line as violation patterns so the
guard script's grep -v filter actually suppresses them. Fixes 6 false
positives in ensemble adapters (dqn, ppo, liquid, kan, tggn, diffusion).

Replace hardcoded 48KB shmem limit in compile_forward_kernel() with
GPU-aware query (max_shared_memory_kb) — matches gpu_experience_collector
pattern. H100 now gets 128-row tiles (was 64), eliminating tile loops
for ≤128-dim layers in the backtest forward kernel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:01:29 +01:00
jgrusewski
a22e6420b6 perf(cuda): Wave 4 — CUDA Graph capture for evaluate_dqn_graphed()
Capture the full DQN backtest step loop (gather → forward → DtoD →
env_step × max_len) as a replayable CUDA Graph:

- evaluate_dqn_graphed(): captures on first call via
  CudaStream::begin_capture/end_capture, replays cached graph on
  subsequent calls. Falls back to evaluate_dqn() on any failure.
- invalidate_dqn_graph(): discards cached graph when weights change.
- SendSyncGraph: newtype wrapper for CudaGraph (single-threaded use).
- Full unrolled capture: each step's step_i32 argument is baked in at
  capture time, avoiding GPU-resident step counter complexity.

Eliminates ~5-10μs per kernel launch × 4 kernels × max_len steps
of CUDA driver overhead per evaluation.

evaluate_baseline.rs: added --cuda-graphs CLI flag to opt in.

14 backtest evaluator tests pass, 0 clippy errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 22:45:13 +01:00
jgrusewski
789fb50dfe perf(cuda): Wave 3 — TMA bulk async tile loads for Hopper (sm_90+)
Add cp.async.bulk.shared::cta.global tile loads guarded by
#if __CUDA_ARCH__ >= 900 in common_device_functions.cuh:

- cooperative_load_tile_tma(): thread-0-only bulk copy via inline PTX,
  freeing 31 warp threads for compute overlap. 16KB chunks with
  commit_group/wait_group barrier.
- cooperative_load_tile_float4(): renamed original for fallback.
- cooperative_load_tile(): dispatch wrapper (compile-time selection).

Architecture-aware NVRTC compilation (compile_ptx_for_device):
- Queries GPU compute capability, passes -arch=compute_XX to NVRTC.
- Enables __CUDA_ARCH__ in kernels so TMA guard activates on Hopper.
- Wired into all 3 runtime compilation sites (experience collector,
  backtest evaluator, PPO collector).

Also fixes pre-existing clippy: vh * 1 identity op in weight estimate.

79 cuda_pipeline tests pass, 0 clippy errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 22:45:13 +01:00
jgrusewski
789dc86589 perf(cuda): Wave 2 — multi-stream overlap, pure-CUDA forward kernels for DQN/PPO/supervised
Multi-stream pipeline (evaluate() closure path):
- Secondary env_stream with CudaEvent sync allows env_step to overlap
  with gather/forward of the next iteration on H100's 132 SMs

Pure-CUDA DQN forward (evaluate_dqn):
- backtest_forward_kernel.cu: warp-cooperative dueling Q forward via NVRTC
- Eliminates candle per-op dispatch overhead, enables future CUDA Graph capture
- evaluate_baseline.rs: auto-detects dueling network and uses pure-CUDA path

Pure-CUDA PPO forward (evaluate_ppo):
- backtest_forward_ppo_kernel.cu: actor MLP → softmax → 45→5 exposure collapse → argmax
- One thread per window, bypasses candle entirely

CUDA supervised signal→action (evaluate_supervised):
- backtest_forward_supervised_kernel.cu: threshold bucketing kernel
- Candle still used for model forward (TFT/Mamba/etc), but argmax is GPU-native

Shared helpers: launch_gather, launch_env_step_on, launch_metrics_and_download
deduplicate code across all four evaluation paths.

914 tests pass, 0 clippy errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 22:05:01 +01:00
jgrusewski
991108471d perf(cuda): lower SM threshold to sm_70 + add warp-cooperative branching DQN forward
- Lower warp kernel SM threshold from sm_90 to sm_70 (covers all modern GPUs)
- Add q_forward_branching_warp_shmem: warp-cooperative branching DQN forward
  with 3 independent advantage heads + shared memory tiling
- Fix online/target dispatch to use warp branching variant when available

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 22:05:01 +01:00
jgrusewski
edd7ceb0f2 perf(cuda): H100 optimization Wave 0+1 — NVTX profiling, L2 cache pinning, dynamic shmem, async double buffer
Wave 0 (NVTX Instrumentation):
- Add ml-core::nvtx module with NvtxRange RAII guard (runtime dlopen, zero overhead when absent)
- Instrument 10 CUDA pipeline hot paths: experience collector, backtest evaluator,
  PPO collector, statistics, training guard, monitoring, replay buffer

Wave 1 (Low-Effort H100 Optimizations):
- L2 cache persistence: pin DQN weights (~23MB BF16) in H100's 50MB L2 via
  cudaCtxSetLimit(CU_LIMIT_PERSISTING_L2_CACHE_SIZE) — 3.5x effective bandwidth
- Dynamic shared memory: GPU-aware tile sizing (228KB H100, 164KB A100, 100KB RTX)
  via CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES opt-in
- Async double buffer: sync_staging() with CUDA stream synchronization before swap

Validation: 0 clippy errors, 1629 tests passed (308+410+911), 0 gpu-hotpath violations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 22:05:01 +01:00
jgrusewski
4709ca8bc2 feat(dqn): enable Branching DQN with 45 factored actions (5×3×3)
Restore 45-action factored space via Branching DQN (Tavakoli 2018),
outputting 11 Q-values (5+3+3) instead of 45. This was reduced to 5
exposure-only actions during debugging and was never intended as permanent.

- Enable use_branching: true by default in DQNConfig and DQNHyperparameters
- Add branching paths to select_action_with_confidence and select_action_inference
- Update agent.rs select_action_factored for branching-aware selection
- Expand CountBonus to per-branch tracking with bonuses_branched()
- Add order_type + urgency distribution tracking in monitoring
- Add DQN_ORDER_ACTIONS=3, DQN_URGENCY_ACTIONS=3, DQN_TOTAL_ACTIONS=45 to CUDA header
- Fix 7 pre-existing clippy doc_markdown errors in regime_conditional.rs
- Fix pre-existing cognitive_complexity in replay_buffer_type.rs (extract helpers)
- Fix flaky GPU test OOM under parallel execution (CPU fallback + test VRAM safety)
- Delete unused flash_attention submodules (block_sparse, causal_masking, etc.)
- Add GPU hot-path guard scripts and ensemble/hyperopt adapter improvements

Tests: ml-dqn 416/0, ml 905/0, clippy 0 errors on both crates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 22:00:13 +01:00
jgrusewski
accb9baef4 feat(cuda): GPU-native PPO + supervised model evaluation & hyperopt fitness
- Add signal_adapter module: PPO 45→5 action aggregation, supervised
  threshold-based signal→action conversion, TFT quantile extraction,
  trade-count-scaled Sharpe fitness function
- Wire GPU backtest fitness into PPO hyperopt adapter (replaces avg
  episode reward)
- Extend all 8 supervised hyperopt adapters with signal_high_bps /
  signal_low_bps tunable thresholds + backtest Sharpe fitness
- Add GPU-accelerated PPO and supervised eval paths in evaluate_baseline
- Update mamba2 argmin tests for expanded 14-param space

+1750/-91 lines across 13 files, 905 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:51:14 +01:00
jgrusewski
a4e9a80d6d fix(test): update mamba2 argmin tests for 14-param space (signal thresholds)
Continuous vectors and expected counts updated from 12 to 14 params
after adding signal_high_bps and signal_low_bps to Mamba2Params.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:12:14 +01:00
jgrusewski
43978e77a3 feat(eval): add GPU-accelerated supervised model evaluation to evaluate_baseline
- evaluate_supervised_fold_gpu(): loads any of 8 supervised models via
  UnifiedTrainable, runs GPU backtest with signal threshold mapping
- TFT uses tft_quantile_to_signal() to extract median quantile before
  threshold comparison; scalar models use signal_to_action_scores() directly
- create_supervised_model() factory + find_supervised_checkpoint() helper
- Main loop dispatches GPU-first for all supervised models when --gpu-eval
- RefCell wrapper bridges &mut self forward() into Fn(&Tensor) closure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:01:26 +01:00
jgrusewski
e690b1c60e feat(hyperopt): add signal threshold params + backtest fitness to all 8 supervised adapters
All supervised hyperopt adapters (TFT, Mamba2, Liquid, KAN, xLSTM, TGGN,
TLOB, Diffusion) now include:
- signal_high_bps and signal_low_bps in ParameterSpace (tunable thresholds)
- backtest_sharpe and backtest_trades fields in Metrics structs
- extract_objective prefers GPU backtest fitness over val_loss when available
- All tests updated (101 passing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:59:38 +01:00
jgrusewski
7750c558c5 feat(cuda): add PPO GPU eval path in evaluate_baseline + hyperopt backtest fitness
- evaluate_ppo_fold_gpu(): loads PPO checkpoint, runs GPU backtest with
  ppo_to_exposure_scores (45→5 collapse), uses GpuBacktestEvaluator
- PPO main loop: tries GPU path first when --gpu-eval (default), falls
  back to CPU if CUDA unavailable or error
- PPOMetrics: backtest_sharpe/backtest_trades fields for GPU walk-forward
- PPOTrainer::run_gpu_backtest(): runs backtest on validation 20% split
- extract_objective(): prefers backtest_fitness when GPU results available,
  falls back to -avg_episode_reward on non-CUDA builds
- 2 new tests: backtest fitness priority + few-trades penalty

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:46:09 +01:00
jgrusewski
448111ca30 feat(hyperopt): add GPU backtest fitness to PPO adapter
Wire GpuBacktestEvaluator into PPO hyperopt trials so the optimizer
ranks candidates by walk-forward Sharpe ratio instead of raw episode
reward.  The PPO actor's 45-action softmax probabilities are collapsed
to 5 exposure scores via ppo_to_exposure_scores before the backtest
loop.  When CUDA is unavailable or the backtest fails, the adapter
falls back to the original -avg_episode_reward objective.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:46:01 +01:00
jgrusewski
c0dd5ef99c feat(cuda): add shared supervised GPU backtest helper in signal_adapter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:41:00 +01:00
jgrusewski
60281dca25 feat(cuda): add signal_adapter module — PPO 45→5, supervised thresholds, TFT quantile, fitness scoring
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:37:44 +01:00
jgrusewski
e4870ea5e9 perf(cuda): make GPU eval default, eliminate all mid-loop GPU→CPU transfers
- Flip --gpu-eval default to true (--no-gpu-eval to opt out)
- Move actions_history scatter-write into env kernel (zero CPU accumulation)
- Remove done-flag periodic download (env kernel handles per-thread)
- Only GPU→CPU transfer is final metrics readback (n_windows × 40 bytes)
- Add spread cost discrepancy warning when GPU path is active

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:03:03 +01:00
jgrusewski
0c85dcf56a Merge branch 'feature/cuda-backtest-plan' 2026-03-11 13:24:04 +01:00
jgrusewski
8c7e907fcf perf(cuda): eliminate GPU→CPU roundtrips from backtest evaluate loop
- gather_states: replace memcpy_dtoh + Tensor::from_vec with DtoD copy
  (cuMemcpyDtoDAsync) — state tensor stays on device, zero CPU touch
- actions: replace to_vec1 + memcpy_htod with DtoD copy from argmax
  tensor directly into actions_buf — eliminates per-step PCIe upload
- batch_q_values (RegimeConditionalDQN): replace CPU-side regime
  classification (to_vec2 + serial loop + sub-batch re-upload) with
  on-device classify_regime_masks_gpu + all-heads forward + masked blend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:05:02 +01:00
jgrusewski
057fefe846 docs(cuda): add review-suggested documentation to epoch state handling
Document known benign race on reset_flags (cross-block __threadfence
not being a grid-wide barrier) and writeback picking an arbitrary
episode's DSR/EMA as the representative seed. Remove dead reads for
epoch_port_value/pos/cash in both standard and warp-cooperative kernel
variants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:50:28 +01:00
jgrusewski
49e214fb8f feat(eval): wire GPU backtester into evaluate_baseline binary
Add --gpu-eval flag that routes DQN fold evaluation through
GpuBacktestEvaluator instead of the per-bar CPU path. The GPU path
uploads the full test fold as a single window, runs the env kernel
loop on-device, and downloads only the final WindowMetrics (10 floats).

Key design choices:
- GPU path uses greedy argmax (not hierarchical softmax); results differ
  slightly from CPU path — this is documented and intentional
- Falls back to CPU path on any GPU error (no silent failures)
- Also adds --initial-capital flag needed by GpuBacktestConfig
- Fix pre-existing clippy::wildcard_enum_match_arm in
  GpuBacktestEvaluator::new (Device::_ → explicit variants)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:41:21 +01:00
jgrusewski
f19cd4b26a test(cuda): add GPU backtest validation tests with synthetic data
Adds crates/ml/tests/gpu_backtest_validation.rs with 6 deterministic
tests that validate GpuBacktestEvaluator produces reasonable metrics:
always-long on uptrend (positive PnL), always-long on downtrend
(negative PnL), always-flat (~zero PnL), multi-window ordering,
extended metrics finiteness/self-consistency, and trade count.

All tests are #[ignore] gated and skip gracefully on CPU-only machines
(CI passes with 6 ignored; intended for GPU development machines).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:38:45 +01:00