Commit Graph

316 Commits

Author SHA1 Message Date
jgrusewski
8c0bed4d2d fix(infra): update training job template to use ci-training-h100 pool
The nodeSelector pointed to non-existent 'ci-training' pool. The actual
Scaleway pool is 'ci-training-h100', matching the CI pipeline template.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:20:15 +01:00
jgrusewski
809295dc5f fix(ml): correct GPU experience path — aligned state_dim, reward tracking, Prometheus label
Three bugs in the GPU experience collection hot path:

1. gpu_batch_to_experiences() had hardcoded state_dim=43 but the CUDA kernel
   outputs states at the ALIGNED dimension (56 with OFI, 48 without). After
   sample 0, every replay buffer entry had corrupted state vectors — the
   network was learning from garbage data.

2. GPU path never called monitor.track_reward(), so mean_reward was always
   reported as 0.0 in epoch logs despite the agent generating real rewards.

3. Action tracking was double-counted (direct array write + track_action_by_exposure),
   inflating diversity metrics by 2x. Consolidated into single bounded call.

Also adds missing app.kubernetes.io/component label to job-template.yaml
so Prometheus training-pods scrape job discovers training pods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:11:01 +01:00
jgrusewski
8926c6e1cf perf(ml): eliminate CPU from DQN training hot path — GPU-resident ops only
GPU experience collector was falling back to CPU because it required a
curiosity VarMap, but curiosity_weight=0.0 means the module is never
created. Fix: make curiosity optional (CuriosityWeightSet::zeros() for
GPU buffers, curiosity_scale=0.0 in kernel config). Also require
explicit binary-tag SHA in Argo training workflow (no "latest" fallback).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 09:15:52 +01:00
jgrusewski
7382ffd1e2 feat(infra): QuestDB metrics sink + monitoring network policies
Add QuestDB ILP sink for training metrics, update Prometheus scrape
configs, and fix network policies for monitoring stack connectivity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 02:42:53 +01:00
jgrusewski
3d43c80264 feat(infra): compile-and-train unified workflow + exclude trading-service from CI deploy
- New compile-and-train-template.yaml: compile + GPU warmup in parallel,
  then fetch-binary → hyperopt → train-best → evaluate → upload-results
- Compile step outputs SHA tag via Argo output parameter, fetch-binary
  uses it directly (no 'latest' package indirection)
- Remove trading-service from CI deploy step — must be explicitly enabled

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:13:43 +01:00
jgrusewski
4976e2e1d7 fix(ml): OFI preload uses adapter's load_ofi_features, not trainer's empty field
Root cause: preload_data() called loader.ofi_features.take() on the internal
DQN trainer, but load_training_data() only loads OHLCV bars — it never
populates ofi_features. The OFI loading is done by the hyperopt adapter's
own load_ofi_features() method.

Fixes:
- preload_data() now calls self.load_ofi_features() directly
- load_ofi_features() uses self.mbp10_data_dir when set (was hardcoded ../mbp10)
- input_dim pre-computation uses OFI-aware size (51 when enabled, 43 otherwise)
- CI 'latest' package: delete-then-upload to avoid GitLab duplicate file issue
- Warn when mbp10_data_dir is set but no OFI features loaded

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:29:22 +01:00
jgrusewski
0491387d27 fix(infra): node-bootstrap DaemonSet + GitLab package auth + latest tag
- Rename node-dns-fix → node-bootstrap, fix nvidia gate race condition
  (always create conf.d/ and write 50-registry.toml, don't gate on
  99-nvidia.toml which doesn't exist on fresh autoscaled GPU nodes)
- Update busybox 1.36 → 1.37
- Fix fetch-binary: use PRIVATE-TOKEN/gitlab-pat (not DEPLOY-TOKEN)
- Fix upload-results: use gitlab-pat (gitlab-ci-token didn't exist)
- Add 'latest' rolling package version in both compile-services and
  compile-training (re-upload after CalVer upload)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:53:31 +01:00
jgrusewski
ebe8b41055 fix(infra): add network policy for GitLab package registry access
Service pods' initContainers need egress to gitlab-webservice-default:8181
to fetch release binaries from the Generic Package Registry. Without this,
curl hangs for 2+ minutes then times out (default-deny-all blocks it).

Covers all app.kubernetes.io/part-of=foxhunt pods in one policy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:15:19 +01:00
jgrusewski
72bc133dba fix(infra): use inputs.parameters for Argo template tag passing
Argo Workflows can't resolve {{tasks.X.outputs}} inside template
bodies — only in DAG task arguments. Pass tag via arguments →
inputs.parameters in compile-services, compile-training,
upload-release, and deploy-services templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:44:52 +01:00
jgrusewski
7a9683d5fb feat(infra): GitLab releases with CalVer auto-versioning
Replace MinIO binary distribution with GitLab Generic Package Registry.
Every code push to main auto-creates a CalVer tag (vYYYY.MM.N),
compiles, uploads binaries to GitLab packages, creates a Release
with auto-generated notes, and deploys via deployment patching.

- New CI templates: create-tag, upload-release
- Modified: compile-services/training upload to GitLab packages
- Modified: deploy-services patches FOXHUNT_RELEASE on deployments
- All 7 service initContainers fetch from GitLab (curl, deploy token)
- Training job-template binary fetch from GitLab (data stays MinIO)
- MinIO retains: sccache, training data, model checkpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:38:41 +01:00
jgrusewski
9a74fda3ab fix(infra): mount training-data-pvc instead of downloading from MinIO
The training-data PVC already has all data (OHLCV, MBP-10, trades).
Mount it read-only at /data in hyperopt/train/evaluate steps instead
of rcloning ~50GB from MinIO every step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:01:55 +01:00
jgrusewski
042c361690 feat(infra): GPU warmup in CI pipeline + OFI data dirs in training workflow
- CI pipeline: add gpu-warmup step parallel to compile-training,
  triggers GPU node autoscale so it's ready when training starts
- Training workflow: add mbp10-data-dir and trades-data-dir parameters,
  download MBP-10 + trades data in all steps (hyperopt, train, evaluate)
- Use parameterized paths consistently (no hardcoded /tmp paths)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:47:55 +01:00
jgrusewski
3f4c39e035 feat(ml): wire OFI data dirs into hyperopt DQN adapter
Add --mbp10-data-dir and --trades-data-dir CLI args to
hyperopt_baseline_rl binary so hyperopt trials can use real
order book and trade data for VPIN/Kyle's Lambda features.

- DQNTrainer: add mbp10_data_dir/trades_data_dir fields + with_ofi_data_dirs() builder
- DQNHyperparameters: pipe through from trainer instead of hardcoded None
- download-trades-job: fix nodeSelector to ci-compile-cpu (platform pool full)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:36:42 +01:00
jgrusewski
c6c550a2be feat(ml): real trade data pipeline for VPIN/Kyle's Lambda + offline RL
Wire Databento Schema::Trades into OFI feature extraction so VPIN and
Kyle's Lambda use real buy/sell classification instead of tick-rule proxy.

Trade data pipeline:
- trades_loader.rs: DbnTrade struct, load_trades_sync(), binary-search
  get_trades_for_bar() for O(log n) time-aligned trade windowing
- ofi_calculator.rs: feed_trade() accumulates real buy/sell pressure
  into VPIN, Kyle's Lambda, and trade imbalance calculators
- data_loading.rs: loads trades from --trades-data-dir, feeds per-bar
  trades to OFI calculator before calculate()
- download-trades-job.yaml: K8s job for ES.FUT trades from Databento
- job-template.yaml: sync trades data from MinIO + --trades-data-dir arg

Offline RL (CQL/IQL):
- experience_dataset.rs: bincode save/load for pre-collected datasets
- iql.rs: Implicit Q-Learning (Kostrikov 2021) — expectile value network,
  advantage-weighted action extraction
- CLI: --offline, --dataset-path, --collect-dataset flags

Cleanup:
- Remove FeatureVector51/MarketFeatureVector type aliases → FeatureVector
- Fix stale dimension comments across 18 files (54→43/51)
- Fix feature_dim default (54→43)

2758 tests pass, 0 compile errors, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:14:46 +01:00
jgrusewski
1ad79493dc feat(infra): training data cache architecture — MinIO → PVC sync
- Expand training-data-pvc from 10Gi → 200Gi (OHLCV + MBP-10 + headroom)
- Add data-sync-job: rclone sync from MinIO → PVC (delta-only, fast repeats)
- Add sync-training-data init container to training job template
  (auto-syncs data from MinIO before each training run)
- Add training-job + data-sync-job NetworkPolicies (MinIO, Tempo, Pushgateway)
- Add app.kubernetes.io/part-of: foxhunt to training pod template
- download_baseline: add --parallel N flag for concurrent Databento downloads
- download_baseline: delete local files after MinIO upload (saves scratch space)
- Bump download job scratch volume to 100Gi

Architecture: Databento → MinIO (source of truth) → PVC (local cache).
First sync pulls everything; subsequent runs only sync deltas (seconds).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:45:30 +01:00
jgrusewski
0d8e59caf5 fix(infra): add NetworkPolicy for data-download jobs, fix pod labels
The download job pod was missing app.kubernetes.io/part-of: foxhunt,
so the default-deny-all egress policy blocked it and MinIO's ingress
policy rejected it. Also removed hostname pinning (was a misdiagnosis).

Added data-download-job NetworkPolicy allowing egress to MinIO:9000
and external HTTPS:443 (Databento API).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 13:22:48 +01:00
jgrusewski
f1c1faa306 fix(infra): use platform node pool for MBP-10 download job
The cluster only has a 'platform' pool, not 'default'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 13:11:39 +01:00
jgrusewski
5829d6378e feat(data): schema-configurable Databento download with MinIO upload
- download_baseline now reads schema from universe TOML config
  (was hardcoded to ohlcv-1m, now supports mbp-10 and other schemas)
- Add --rclone-dest flag for direct upload to MinIO after each download
- Add config/universe-es-mbp10.toml: ES.FUT MBP-10, same date range
- Add infra/k8s/training/download-mbp10-job.yaml: K8s Job to download
  ES.FUT MBP-10 data in-cluster and upload to MinIO

Usage:
  kubectl apply -f infra/k8s/training/download-mbp10-job.yaml

Prereqs: databento-credentials secret, download_baseline binary in MinIO

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:19:46 +01:00
jgrusewski
c63611fb03 fix(dashboard): overhaul training Grafana dashboard layout and visuals
- Remove all hardcoded Y-axis min/max bounds (41 removals) — dynamic scaling
- Eliminate Hyperopt section: merge into Training Status + Run Summary
- Deduplicate trial progress (3 panels → 1 gauge + 1 stat)
- Combine ML Jobs + Errors into single panel
- Add Current Trial and Hyperopt Elapsed to status bar
- Add Best Objective Δ (deriv) trend indicator
- Smooth line interpolation + gradient fills on all timeseries
- Stacked area for Action Distribution, gradient fill for Replay Buffer
- Shared crosshair tooltips, consistent threshold colors
- Status bar: stat panels with sparklines, trial before epoch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:14:59 +01:00
jgrusewski
fbb674f9e2 fix(infra): make gpu-warmup tolerant of missing nvidia-smi
nvidia-smi is driver-mounted by the GPU operator, which may not be
ready when the warmup pod starts on a fresh autoscaled node. The
warmup's purpose is just triggering autoscale, not GPU validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:56:35 +01:00
jgrusewski
f356ce157c fix(infra): restore rclone line continuations before --transfers=8
Previous fix removed ALL trailing backslashes from --s3-no-check-bucket,
but 3 of 6 occurrences need the continuation for --transfers=8 on the
next line. Restores \ on lines where --transfers follows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:45:33 +01:00
jgrusewski
1d87fa41bc fix(infra): remove trailing backslash in training workflow rclone commands
Same bug as service manifests — \\ after --s3-no-check-bucket caused
chmod to be parsed as rclone args. Fixed in 6 places.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:35:27 +01:00
jgrusewski
5dbe529ee6 fix(ci): rebuild CI builder images with mold linker
Both Dockerfiles already install mold v2.35.1 but the registry images
are stale builds without it. This change triggers rebuild-ci-builder
and rebuild-ci-builder-cpu pipeline steps via detect-changes.

.cargo/config.toml uses -fuse-ld=mold — without mold in the image,
linking falls back to the system default (slower).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:20:09 +01:00
jgrusewski
b31329931f fix(infra): remove MinIO TLS, fix sccache 0% cache hits, update pool selectors
- Remove all HTTPS/TLS from MinIO (plain HTTP for internal cluster traffic)
- Fix sccache 0% cache hit rate (rustls rejected self-signed MinIO cert)
- Remove hardcoded URLs from k8s_dispatcher.rs (S3_ENDPOINT, TRAINING_RUNTIME_IMAGE,
  CALLBACK_ENDPOINT now required env vars)
- Update GitLab registry S3 credentials to HTTP endpoint
- Fix PVC manifest (20Gi → 100Gi to match cluster)
- Fix nodeSelector: infra/foxhunt → platform (match actual node pool)
- Fix rclone trailing backslash causing chmod to be parsed as rclone args
- Remove minio-ca-cert ConfigMap references from all manifests
- Update trading-service GPU overlay to l40s pool

20 files changed, -118 lines net

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:53:05 +01:00
jgrusewski
4e0d1fcbe6 fix(ci): add imagePullPolicy: IfNotPresent to training workflow
Kubernetes defaults to Always for :latest tags, forcing registry
round-trips that fail on fresh GPU nodes where containerd HTTP-only
registry config has a race condition with HTTPS fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:49:34 +01:00
Administrator
4658d7e914 Merge branch 'feature/action-diversity-fix' into 'main'
feat(ml): multi-window backtest + top-K ensemble training

See merge request root/foxhunt!2
2026-03-06 07:48:06 +00:00
jgrusewski
84366d8dd8 fix(infra): pin CI sensor pod to DEV1-L platform nodes
The Argo Events sensor had no nodeSelector and randomly landed on the
H100 GPU node, preventing autoscale-down. Pin it to DEV1-L to avoid
wasting expensive GPU node hours on a lightweight event listener.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 08:45:59 +01:00
jgrusewski
5a9fa1534b feat(ml): multi-window backtest objective + top-K ensemble training
Multi-window backtest: splits validation data into 3 non-overlapping
windows and aggregates with mean(Sharpe) - 0.5*std(Sharpe), penalizing
inconsistency and reducing overfit to a single data segment.

Top-K ensemble: hyperopt now emits top_k_params (top 5 trials) in JSON
output. train_baseline_rl gains --ensemble-top-k flag to train multiple
models per fold from different hyperopt configs, saving checkpoints as
dqn_ensemble_{k}_fold_{n}.safetensors.

Workflow template: adds ensemble-top-k parameter (default 5) and passes
--ensemble-top-k to the train-best step.

2720 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 08:42:03 +01:00
jgrusewski
2b77a7fbe1 fix(dashboard): clamp degenerate outliers in training metrics panels
Add clamp_max() to PromQL queries and hard Y-axis limits to prevent
early-epoch degenerate values from blowing up panel scaling (Sharpe
showing 12 instead of 1.3, Profit Factor at 30k).

Run Summary: clamp_max on Best Val Loss (5), Sharpe (5), Profit Factor (20)
Training Quality: clamp_max on Epoch Sharpe (5), Sortino (10), PF (20)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 02:22:21 +01:00
jgrusewski
5323cf11e7 fix(dashboard): convert Run Summary to smooth timeseries, 3x2 layout
Replace stat panels with timeseries using smooth line interpolation,
gradient fill, and multi-tooltip. Layout changed from 6x1 to 3x2 grid.
Legends show model/fold only when multiple series exist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 01:37:31 +01:00
jgrusewski
9067402284 feat(dashboard): add Run Summary row to training dashboard
Add 6 stat panels showing overall training run metrics: Best Val Loss,
Best Sharpe, Best Win Rate, Min Max Drawdown, Total Epochs, and Best
Profit Factor. Placed between Training Status and Training Curves rows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 01:28:29 +01:00
jgrusewski
351bdaf8f1 feat(infra): add GPU warmup step to training pipeline
Runs nvidia-smi on GPU node in parallel with fetch-binary, triggering
H100 autoscale during compilation so the node is ready when hyperopt
starts. Exits immediately to free GPU resources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 00:07:41 +01:00
jgrusewski
08a927639e fix(ci): POSIX-compatible kubectl detection in deploy step
The foxhunt-runtime image runs as non-root user 'foxhunt' and uses
/bin/sh (dash), not bash. Two issues:
1. &>/dev/null is bash-only — use >/dev/null 2>&1 for POSIX sh
2. Fallback download to /tmp (writable), not /usr/local/bin (root-only)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:26:35 +01:00
jgrusewski
7b60fd5f86 fix(ci): Docker build uses init container + emptyDir instead of PVC
The build-ci-image template used volumeClaimTemplates (PVC) which
weren't inherited when called via templateRef from ci-pipeline.

Restructured to single pod: init container (alpine/git) clones repo
into emptyDir, main container (kaniko) builds and pushes image from
the same volume. No PVC needed, works correctly via templateRef.

Tested: foxhunt-runtime image rebuilt successfully with kubectl.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:11:55 +01:00
jgrusewski
9cd4da9acf fix(ci): restructure Docker build to single pod with emptyDir
build-ci-image used volumeClaimTemplates (PVC) shared between a
git-clone pod and a kaniko-build pod in a DAG. When called via
templateRef from ci-pipeline, the VCT wasn't inherited, causing
"volume 'workspace' not found" errors.

Fixed by merging into a single pod: init container (git clone) +
main container (kaniko build) sharing an emptyDir volume. No PVC
needed, works correctly when called via templateRef.

Also removed stale compile-training-template.yaml reference from
kustomization (file doesn't exist, template is inline in ci-pipeline).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:58:42 +01:00
jgrusewski
171fe86194 fix(ci): bake kubectl into runtime image for faster deployments
Add kubectl v1.31.4 to foxhunt-runtime Dockerfile so deploy step
doesn't need to download it each run. Deploy step falls back to
curl download if kubectl not found (for current image version).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:49:51 +01:00
jgrusewski
4e71cbf549 fix(ci): use runtime image for deploy step, add podGC to sensor
- Deploy step: use foxhunt-runtime image (cached on platform node) +
  curl kubectl, replacing bitnami/kubectl:1.31 which doesn't exist.
- Sensor: add podGC:OnPodCompletion and ttlStrategy to workflow spec
  (not inherited from WorkflowTemplate via workflowTemplateRef).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:46:11 +01:00
jgrusewski
a77c873da4 fix(ci): add deploy step, podGC, move compile-services to ci-compile-cpu
Three issues prevented services from being deployed after push:

1. No deploy step: pipeline compiled + uploaded binaries to MinIO but
   never restarted service deployments. Added deploy-services step
   (bitnami/kubectl) that runs rollout restart after compile-services.

2. compile-services couldn't schedule: targeted platform node (4 CPU,
   6Gi allocatable) but requested 6Gi memory. Moved to ci-compile-cpu
   (POP2-32C-128G) alongside compile-training — both fit simultaneously
   (28/32 CPU, 48/128Gi).

3. No podGC: completed Argo pods held resources indefinitely, blocking
   subsequent pipeline steps. Added podGC:OnPodCompletion.

Also: detect-changes now triggers service rebuild when CI pipeline
template or k8s service manifests change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:34:44 +01:00
jgrusewski
5d5cce72d2 fix(infra): auto-restart containerd on GPU nodes for registry config
DaemonSet init container now:
- Detects GPU nodes (99-nvidia.toml in conf.d)
- Creates v3-compatible registry config drop-in
- Restarts containerd via chroot if config files changed
- Idempotent: skips restart if files already exist

Requires hostPID + privileged for chroot /proc/1/root.
On new nodes, first run creates files + restarts containerd
(kills pod), second run finds files unchanged (no restart).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:12:17 +01:00
jgrusewski
248b2fec70 fix(ml,infra): handle early stopping in hyperopt, GPU containerd registry
- Hyperopt: catch early stopping errors and return penalty metrics
  instead of aborting entire run. Trials that stop early are scored
  as poor (objective=-500) so optimizer avoids those configs.
- DaemonSet: detect GPU nodes (NVIDIA conf.d overlay) and create
  v3-compatible registry config drop-in for containerd v2.1+.
  Old grpc.v1.cri.registry path is silently ignored by containerd v2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:07:09 +01:00
jgrusewski
168b552d1a fix(infra): node DNS + containerd registry for cluster-internal images
Kapsule nodes use nameserver 127.0.53.53 which resolves external DNS
but returns NXDOMAIN for .svc.cluster.local. Containerd uses node DNS
for image pulls, causing ErrImagePull for cluster-internal registry refs.

Deploy node-dns-fix DaemonSet (kube-system) that:
1. Points /etc/resolv.conf to kube-dns ClusterIP (10.32.0.10)
2. Creates containerd certs.d config for HTTP GitLab registry
3. Watches for Kapsule node reconciliation resets (every 30s)
4. Restores original resolv.conf on SIGTERM

Also bump compile-services memory: 6Gi→10Gi limit (was OOM-killed at 5.7GB).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:47:41 +01:00
jgrusewski
0070a0117e feat(api): add api_uptime_seconds metric, replace web-gateway panels in cockpit
- Add api_uptime_seconds gauge to API service (5s update interval),
  matching the pattern used by trading/backtesting/ml-training services
- Remove obsolete Web Gateway Uptime and Active WebSocket Connections
  panels from cockpit (web-gateway is not deployed)
- Add API Gateway Uptime (api_uptime_seconds) and API Auth Rate
  (api_auth_requests_total) panels in their place

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:27:07 +01:00
jgrusewski
34b881fa14 fix(dashboards): show node names instead of IPs in infrastructure panels
Join node metrics with node_uname_info to resolve instance IPs to
hostnames (e.g. scw-foxhunt-platform-694db...) in all 10 node-level
panels: CPU, Memory, Disk I/O, Network I/O, Load Average, Disk Usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:00:52 +01:00
jgrusewski
d678f7d28a fix(monitoring): filter completed Argo pods from Prometheus scrape targets
Add __meta_kubernetes_pod_phase=Running filter to training-pods job.
Completed/failed Argo workflow step pods were showing as DOWN targets
because their containers are no longer running to serve /metrics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:10:20 +01:00
jgrusewski
2b77df7dda fix(dashboards): correct metric prefixes, gRPC code filters, and service labels
- Replace api_gateway_ with api_ prefix to match actual metric exports (cockpit, observability)
- Change grpc_code!="OK" to grpc_code!="0" — gRPC uses numeric status codes (cockpit, trading)
- Update gRPC service filter to actual exported_service labels: trading-agent-service,
  broker-gateway, backtesting-service, ml-training-service, data-acquisition-service (trading)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:02:32 +01:00
jgrusewski
9dc4d2585f fix(infra): rewrite dashboards with verified metrics, fix KSM + internal DNS
Rewrite all 5 Grafana dashboards using only confirmed-existing Prometheus
metric names (1023 metrics inventoried). Dashboards now use hardcoded
datasource UIDs instead of unresolvable ${DS_*} template variables.

- Cockpit: 38 panels (service health, gRPC, Argo CI/CD, trading, metrics)
- Training: 33 panels (epochs, loss, Sharpe, Q-values, GPU, hyperopt)
- Trading: 5 rows (overview, latency, gRPC pipeline, data acq, backtesting)
- Infrastructure: 25 panels (cluster, nodes, workloads, storage, GPU, Prometheus)
- Observability: 22 panels (API gateway auth/security/routing, Loki, Tempo)

Fix kube-state-metrics: add part-of label for netpol, fix nodeSelector
(infra→platform), increase memory limit (128→256Mi for OOM), add K8s API
egress rules covering both 10.32.0.0/16 and 172.16.0.0/16 CIDR ranges.

Add training-pods pod-based scrape job for ephemeral Argo workflow pods
exposing metrics on port 9094.

Migrate all image references from localhost:30500 to internal DNS
(gitlab-registry.foxhunt.svc.cluster.local:5000) across 14 YAML files.

Fix import.sh ConfigMap name (grafana-dashboards-infra → infrastructure).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:55:06 +01:00
jgrusewski
b3c85d4f7c fix(infra): resolve dashboard datasource UIDs, fix Grafana→Prometheus netpol
- Remove duplicate annotated-pods and gitlab-annotated-pods scrape jobs
  (all targets already covered by dedicated jobs)
- Drop Argo controller from foxhunt-services job (dedicated HTTPS job exists)
- Resolve datasource variable placeholders to actual UIDs in dashboard JSON
- Add Ingress rule to Prometheus netpol allowing Grafana on port 9090

Targets: 49 → 18 (zero duplicates)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:43:25 +01:00
jgrusewski
26d2ac7a5c feat(infra): redesign Grafana dashboards, consolidate to single Prometheus
Replace 11 overlapping legacy dashboards with 5 focused dashboards:
- Operations Cockpit (services, Argo CI/CD, resources, auth)
- Trading & ML Intelligence (signals, execution, risk, gRPC)
- Training & CI/CD (training curves, GPU, hyperopt, Argo pipelines)
- Infrastructure & Cluster (nodes, pods, storage, network)
- Observability & API Gateway (logs/Loki, traces/Tempo, API metrics)

Remove gitlab-prometheus-server dependency — single Prometheus instance
with all scrape configs including Argo Workflows (HTTPS + skip verify).
Update Grafana datasource and import.sh for new dashboard structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:50:52 +01:00
jgrusewski
b6b3fbd463 fix(ml,infra): GPU-resident hierarchical softmax, imagePullPolicy Always
Rewrite batch_hierarchical_softmax_actions to keep all sampling on GPU:
reshape [N,45]→[N,5,9], max-pool→[N,5] exposure Q, Gumbel-max over
exposures, parallel Gumbel-max over all sub-actions, gather chosen
exposure's sub-action. Only CPU transfer: N flat indices.

Add imagePullPolicy: Always to compile-services and compile-training
containers so rebuilt builder images are never stale-cached.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:31:25 +01:00
jgrusewski
5215366b22 fix(infra): use proxy_pass for API gateway to support gRPC-web
grpc_pass only handles native gRPC (HTTP/2 frames). The web dashboard
uses gRPC-web via Connect protocol (HTTP/1.1 POST requests). Switch
api.fxhnt.ai nginx block to proxy_pass so tonic_web::GrpcWebLayer on
the API service can handle the protocol conversion.

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