Commit Graph

80 Commits

Author SHA1 Message Date
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
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
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
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
jgrusewski
6d731b860d fix(infra): use NodePort localhost:30500 for all container image refs
containerd on Kapsule nodes uses host DNS which can't resolve
.svc.cluster.local names. Switch all image references from
gitlab-registry.foxhunt.svc.cluster.local:5000 to localhost:30500
(NodePort on the GitLab registry). Also make training runtime image
configurable via TRAINING_RUNTIME_IMAGE env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:31:54 +01:00
jgrusewski
889ab4588b feat(infra): add web-dashboard k8s deployment on platform pool
- nginx pod serves Vite-built static assets from MinIO S3
- initContainer fetches dist/ from s3://foxhunt-binaries/web-dashboard/
- SPA routing via try_files, aggressive caching for hashed assets
- dashboard.fxhnt.ai proxied to web-dashboard:80 via tailscale nginx
- CI pipeline: build-web-dashboard task (npm ci + build + rclone upload)
- detect-changes: needs-dashboard output for web-dashboard/ paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:56:59 +01:00
jgrusewski
dc66780465 fix(infra): route dashboard.fxhnt.ai to web-gateway instead of Grafana
Split the combined grafana+dashboard nginx block so dashboard.fxhnt.ai
proxies to web-gateway:3000 (the actual trading dashboard) instead of
Grafana.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:53:34 +01:00
jgrusewski
68b6aa8313 feat(infra): migrate container registry from SCW to internal GitLab
Full migration off Scaleway Container Registry to internal GitLab
registry backed by MinIO S3. All 4 images (ci-builder, ci-builder-cpu,
foxhunt-runtime, foxhunt-training-runtime) rebuilt in internal registry.

Registry & images:
- All image refs → gitlab-registry.foxhunt.svc.cluster.local:5000/root/foxhunt/
- imagePullSecrets: scw-registry → gitlab-registry
- Kaniko build template: two-step DAG (git-clone → kaniko-build) with shared PVC
- Kaniko layer cache enabled at root/foxhunt/cache
- AWS_ACCESS_KEY_ID: $SCW_ACCESS_KEY → $MINIO_ACCESS_KEY in .gitlab-ci.yml

Network policies:
- ci-pipeline: add HTTP/80, registry/5000, webservice/8181 egress rules

DNS & Tailscale proxy cleanup:
- Remove ci, prometheus, monitor DNS records (no longer exposed)
- Rename s3 → minio DNS record
- Remove Argo UI, Prometheus, monitor nginx server blocks
- Remove argo-htpasswd volume mount
- Tailscale proxy nodeSelector: infra → platform

Terraform cleanup:
- Delete infra/modules/registry/ (SCW CR namespace)
- Delete infra/modules/object-storage/ (SCW S3 buckets)
- Delete infra/modules/secrets/ (SCW secrets)
- Delete corresponding live configs
- TF state backend: S3 → GitLab HTTP

Argo workflows:
- Add events/ (GitLab push eventsource + ci-pipeline sensor)
- ci-pipeline + training templates: SCW → internal registry
- Delete obsolete compile-training-template.yaml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:52:24 +01:00
jgrusewski
57e22c01a8 refactor: update K8s, CI, Docker, Prometheus, scripts, and FXT CLI for api rename
- K8s: rename api-gateway → api manifests, delete web-gateway, update network policies
- CI: rename compile/deploy jobs, delete web-gateway jobs
- Docker: rename service in compose files
- Prometheus: update scrape targets and alert rules
- Scripts: update binary references in build/test/cert scripts
- FXT CLI: rename api_gateway_url → api_url (with serde alias for compat)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:46:36 +01:00
jgrusewski
70f5f4ff52 feat(argo): add basic auth login for Argo UI
Add nginx basic auth (htpasswd) to ci.fxhnt.ai proxy block and
switch Argo to server auth mode. Login: jgrusewski / Welcome01.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:58:40 +01:00
jgrusewski
370752f253 feat(infra): expose Argo Workflows UI at ci.fxhnt.ai
Rename DNS record from argo→ci and update nginx proxy server_name
to match. Applied via terragrunt and kubectl.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:58:40 +01:00
jgrusewski
1ad77b6427 fix(ci): request nvidia.com/gpu in GitLab runner pod specs
The GPU runners used runtime_class_name=nvidia for CUDA access but
didn't request nvidia.com/gpu as a K8s resource, allowing multiple
training pods to share a GPU without K8s awareness. Add pod_spec
patches to request GPU resources properly so K8s enforces mutual
exclusion between GitLab CI and Argo training jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:58:40 +01:00
jgrusewski
a2468846e1 feat(argo): add Argo Workflows infrastructure for training orchestration
- Helm values (controller + server on platform node, MinIO artifact repo)
- WorkflowTemplate: parameterized 5-step DAG (fetch→hyperopt→train→eval→upload)
- Nginx proxy for argo.fxhnt.ai → Argo Server :2746
- DNS A record for argo.fxhnt.ai
- MinIO bucket foxhunt-training-results for Argo artifacts
- Kustomization for kubectl apply -k

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:58:40 +01:00
jgrusewski
2f75071551 fix(ml): keep DQN and PPO training pipelines in BF16 on Ampere+ GPUs
On Ampere+ GPUs the training dtype is BF16.  Network forward passes
with BF16 inputs return BF16 tensors, but all loss-path arithmetic
(rewards, dones, gamma, PER weights, Huber constants, atoms, clip
epsilon) was created as F32 from Tensor::from_vec.  Candle forbids
mixed-dtype binary ops, causing "dtype mismatch in {mul,sub,add}"
on every training step.

DQN fixes (7 mismatch sites):
- Cast current_q_values to F32 immediately after forward pass
- Cast all target network outputs (standard, dueling, C51, IQN) to F32
- Keep rewards/dones/gamma/weights/atoms/half/delta as F32 (remove
  .to_dtype(training_dtype) casts — now use DType::F32 sentinel)
- Entropy regularization and CQL paths now match (F32 + F32)

PPO fixes (3 mismatch sites):
- Use DType::F32 for clip epsilon one_tensor (was training_dtype BF16)
- Cast critic.forward() output to F32 in both MLP and LSTM value loss
- Cast target_returns to F32 for symlog/normalization path

Infra: revert runner-h100 from SXM2 (zero Scaleway quota) back to
ci-training-h100 PCIe pool.

2704 ml lib tests pass, 260 PPO tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:52:56 +01:00
jgrusewski
cc209aec7e feat(infra): replace PVC binary distribution with MinIO S3 fetch
Eliminate foxhunt-binaries and training-binaries PVCs — services and
training jobs now fetch binaries from MinIO via rclone initContainers.
This removes L40S GPU autoscale-for-PVC-writes, removes RWO node
affinity constraints, and requires zero image rebuilds.

Changes:
- .gitlab-ci.yml: replace ~115 lines of binary-writer pod logic with
  aws s3 cp to MinIO (~25 lines)
- 8 service YAMLs + 2 GPU overlays: add rclone initContainer + emptyDir
- Training job template: MinIO rclone fetch replaces PVC copy
- Delete foxhunt-binaries-pvc.yaml and training-binaries-pvc.yaml
- Add s3.fxhnt.ai DNS record (Terraform) and nginx proxy block
- Replace pod-writer-deploy skill with MinIO-based deploy skill

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:46:57 +01:00
jgrusewski
dd10497cfd fix(ml): cast Bellman target to F32 before TD error sub on BF16 GPUs
BUG #41 kept forward pass in F32 for autograd, but the target-side
tensors (reward, gamma, done, next_q) were cast to BF16 via `dtype`.
The `state_action_values.sub(&target_q_values)` then hit F32-vs-BF16
mismatch on Ampere+ GPUs, causing every training step to fail silently.

Fix: `.to_dtype(state_action_values.dtype())` on the detached target.
Safe because target is detached (no autograd graph to break).

Also: H100 runner → SXM2 pool, GPU availability checker script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:29:15 +01:00
jgrusewski
1931d93d66 feat(ci): add 2×H100 GPU pool for multi-GPU training
Pool ci-training-h100x2 (H100-2-80G, 160GB VRAM total).
MultiGpuConfig::detect() in ml crate auto-enables data parallelism.
Tags: kapsule,h100x2. Autoscale 0→1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:32:26 +01:00
jgrusewski
2381c61bb6 refactor(ci): rename GPU runner tags from 'gpu' to 'l40s' for clarity
Clear separation: l40s tag → L40S pool, h100 tag → H100 pool.
Updated runner-rl-values.yaml and CI base templates to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:48:25 +01:00
jgrusewski
a563c64dd3 feat(ci): add H100 GPU pool for hyperopt jobs
- Create ci-training-h100 runner (runner-h100-values.yaml)
- Route hyperopt-dqn and hyperopt-ppo to H100 via kapsule,h100 tags
- H100 is ~2x faster and cheaper per run vs L40S for hyperopt workloads

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:41:37 +01:00
jgrusewski
66d6d0f2a5 chore: delete monitoring_service — absorbed into API Gateway
Remove from workspace members, delete K8s deployment, remove nginx routing.
Training metrics and system health now served directly by API Gateway.

Changes:
- Cargo.toml: remove services/monitoring_service from workspace members
- services/monitoring_service/: deleted entirely (6 files)
- infra/k8s/services/monitoring-service.yaml: deleted
- infra/k8s/network-policies/monitoring-service.yaml: deleted
- infra/k8s/network-policies/api-gateway.yaml: remove egress rule to monitoring-service
- infra/k8s/network-policies/web-gateway.yaml: remove egress rule to monitoring-service
- infra/k8s/services/api-gateway.yaml: remove stale MONITORING_SERVICE_URL env var
- infra/k8s/gitlab/tailscale-proxy.yaml: redirect monitor.fxhnt.ai to api-gateway:50051
- .gitlab-ci.yml: remove monitoring_service from compile, copy, and deploy loops
- services/trading_service/src/services/monitoring.rs: update stale comments to
  reference api_gateway (not monitoring_service) as training metrics host

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:26:00 +01:00
jgrusewski
85725abd8f feat(monitoring): per-epoch Prometheus metrics + CI scrape plumbing
- DQN/PPO trainers now record epoch, loss, val_loss, batch/s every epoch
- CI training jobs get Prometheus scrape annotations via runner overrides
- Allow Prometheus (foxhunt namespace) to scrape foxhunt-ci pods
- Skip no-model metrics in monitoring service session grouping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:10:52 +01:00
jgrusewski
6b67f6193a infra: expose monitoring service via monitor.fxhnt.ai Tailscale proxy
Add DNS record, nginx gRPC proxy block, network policy for Tailscale
ingress, and auto-detect fxhnt.ai in fxt monitor URL derivation.
Show GPU telemetry even when no training sessions are active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:56:40 +01:00
jgrusewski
091167bb23 fix(ci): align training job tags with runner (kapsule-rl → kapsule)
Runner #2 already has tags [kapsule, gpu] but CI jobs still used
kapsule-rl. Also removes stale minio-ca-cert volume from runner values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:45:19 +01:00
jgrusewski
b4dc9766f9 fix(infra): remove dead Cockpit remote_write from GitLab Prometheus
The remoteWrite block had placeholder values (COCKPIT_METRICS_PUSH_URL,
COCKPIT_PUSH_TOKEN) that were never replaced, causing Prometheus to
spam "Failed to send batch" warnings every minute. Cockpit was replaced
by self-hosted Grafana+Prometheus+Loki+Tempo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:26:17 +01:00
jgrusewski
d501d53c9d chore(infra): remove dead Cockpit TF, CI-CD dashboards, stale Grafana configs
- Delete infra/modules/cockpit/ and infra/live/production/cockpit/
  (Scaleway Cockpit replaced by self-hosted Grafana+Prometheus+Loki+Tempo)
- Delete CI-CD dashboards (foxhunt-ci-pipelines, gitlab-services) and
  grafana-dashboards-cicd ConfigMap from K8s
- Delete config/grafana/ — unreferenced old dashboards (15 files)
- Delete config/monitoring/grafana/ — unreferenced DQN staging dashboard
- Delete crates/ml/grafana/ — unreferenced ML performance dashboard
- Delete services/broker_gateway_service/grafana/ — unreferenced
- Delete .claude/agents/devops/ci-cd/ — GitHub Actions agent (we use GitLab CI)
- Fix grafana-values.yaml: dashboard folder GitLab → Foxhunt,
  hardcoded adminPassword → K8s secret (grafana-admin),
  gitlab-overview → node-exporter (correct name for gnetId 1860)
- Remove CI-CD group from import.sh ConfigMap groups and API fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:13:40 +01:00
jgrusewski
03fa993d54 chore(grafana): rotate admin password to random value
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:02:21 +01:00
jgrusewski
216240bcd5 feat(grafana): migrate from SQLite/PVC to PostgreSQL backend
Grafana now stores users, preferences, and state in our existing
PostgreSQL instance (dedicated 'grafana' database). This eliminates
the 2Gi PVC dependency — all persistent state lives in Postgres,
dashboards in ConfigMaps, datasources in Helm values.

Also adds Grafana to Postgres NetworkPolicy ingress allowlist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:01:11 +01:00
jgrusewski
c608e62082 fix(grafana): restore full values file with sidecar, datasources, tolerations
The Grafana PVC was lost during cleanup (orphaned PV deletion).
Dashboards survived (ConfigMap-based), but user accounts and
datasources were lost.

This commit captures all Helm values previously set via --set:
- Sidecar config with foldersFromFilesStructure for folder organization
- Loki + Tempo datasources alongside Prometheus
- Platform node toleration for gitlab taint

Also fixed CI/CD folder annotation (slash caused nested directory).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:33:42 +01:00
jgrusewski
5084dcd3b2 infra: migrate Postgres to platform pool with PVC migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:21:20 +01:00
jgrusewski
17091500ed infra: move Grafana to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:15:39 +01:00
jgrusewski
fea630e9ff infra: move tailscale proxies to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:08:20 +01:00
jgrusewski
2a6ec55755 infra: split foxhunt-secrets into per-concern secrets
db-credentials, jwt-secret, redis-credentials, s3-credentials.
Each service only references the secrets it needs.
Values are REPLACE_IN_DEPLOY markers — real values
injected by scripts/deploy-secrets.sh.

Also updated references in postgres.yaml, migrate.yaml,
and postgres-init.yaml to use db-credentials.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:41:13 +01:00
jgrusewski
a27ff8790c fix(ci): restore nvidia runtime_class_name on RL runner
RL runner only handles GPU training jobs, so global nvidia runtime
is safe and required (KUBERNETES_RUNTIME_CLASS_NAME override wasn't
being applied). Main runner keeps overwrite-allowed pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:37:58 +01:00
jgrusewski
972c3cb3cc fix(ci): correct pool naming — all training to ci-training, compile to ci-compile-cpu
Pool mapping:
- ci-compile-cpu (POP2-32C-128G): Rust compile, web dashboard, manifest
- ci-compile (L4): CUDA compile with stubs only
- ci-training (L40S): ALL training (RL + supervised)

Main runner default → ci-compile-cpu
RL runner default → ci-training
.train-rl-base → explicit ci-training node selector

Replaced all stale ci-rl references with correct pool names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:21:14 +01:00
jgrusewski
a36fce0b87 fix(infra): increase Tempo memory to 1Gi, RL runner CPU limits to 8000m
Tempo was OOMKilled every ~30 min at 512Mi, causing web-gateway OTLP
export errors. Increased to 1Gi.

RL runner had cpu_request_overwrite_max_allowed=4000m but hyperopt RL
jobs need 6000m for parallel PSO trials. Increased to 8000m.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:04:26 +01:00
jgrusewski
cfdd878fff fix(ci): move nvidia runtime from global to per-job
Remove runtime_class_name="nvidia" from runner configs (applied to ALL
pods, broke compile on CPU-only ci-compile-cpu nodes). Instead use
runtime_class_name_overwrite_allowed + KUBERNETES_RUNTIME_CLASS_NAME
per-job on GPU templates (.train-rl-base, .train-validate-base).

Also routes build-web-dashboard and write-manifest to ci-compile-cpu.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:43:24 +01:00
jgrusewski
74a572a5c4 feat(infra): enable MinIO TLS with self-signed CA for in-cluster HTTPS
Switch all MinIO communication from HTTP to HTTPS across the entire stack:
- MinIO deployment: mount TLS secret, tcpSocket probes, HTTPS init-buckets
- 11 service YAMLs: HTTPS rclone endpoint + CA cert volume mount
- Training job template + train.sh: HTTPS for fetch-binaries and uploader
- CI pipeline (.gitlab-ci.yml): all 7 rclone exports use HTTPS + CA cert
- GitLab runner values: minio-ca-cert ConfigMap volume for CI pods
- Rust: CA cert loading via MINIO_CA_CERT_PATH in training_uploader,
  storage backend, data_acquisition uploader, and k8s_dispatcher
- Cert generation script (infra/scripts/generate-minio-tls.sh)

Fixes training uploader S3 upload failures caused by with_allow_http(false)
connecting to an HTTP endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:56:06 +01:00
jgrusewski
fbd6ebe13a fix(gitlab): disable KAS at global level to stop Sidekiq NotifyGitPushWorker errors
The existing `global.appConfig.gitlab_kas.enabled: false` only affected
the KAS subchart config but was ignored by the chart template that
generates gitlab.yml. Adding `global.kas.enabled: false` properly sets
`gitlab_kas.enabled: false` in gitlab.yml and removes the orphaned
gitlab-kas Service, stopping ~5 GRPC::Unavailable errors per git push.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:35:27 +01:00
jgrusewski
1aef51f99b fix(stubs): implement 15 production stubs, fix routing, delete placeholders
Web-gateway routing:
- Point TRADING_SERVICE_URL at api-gateway (proto mismatch fix)
  Web-gateway uses foxhunt.tli.TradingService proto but was connecting
  directly to trading-service which implements trading.TradingService.
  api-gateway already proxies Subscribe* → Stream* correctly.

GitLab KAS:
- Disable gitlab_kas in appConfig to stop sidekiq NotifyGitPushWorker
  errors (KAS pod was already disabled but Rails still tried to connect)

Trading service monitoring (3 stubs → real):
- AcknowledgeAlert: real alert lookup + state mutation in shared store
- GetActiveAlerts: returns actual active alerts from in-memory store
- StreamAlerts: now persists generated alerts (capped at 1000 entries)

Trading service ML streams (2 stubs → real):
- StreamModelMetrics: emits real inference_count, error_count, latency
  per model every N seconds from the RuntimeModelInfo registry
- StreamSignalStrength: emits per-symbol signal aggregation from model
  ensemble weights and latency confidence

Backtesting service:
- stop_backtest: real CancellationToken cancellation (was no-op)
  Tokens stored per-backtest, execute_backtest wraps strategy call
  in tokio::select! for immediate cancellation

Deleted 7 empty placeholder files:
- 4 Wave D regime stubs (dynamic_stops, ensemble, performance_tracker,
  position_sizer) — comment-only files, never wired
- 2 Wave 3 feature stubs (microstructure, statistical)
- 1 PPO stub (unified_ppo.rs — empty struct definitions)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:47:31 +01:00
jgrusewski
48316d6874 feat(infra): add api.fxhnt.ai DNS + gRPC reverse proxy for API Gateway
Add nginx server block for api.fxhnt.ai with grpc_pass to the
api-gateway ClusterIP service. Add Scaleway DNS A record via Terraform
module. Fix fxt gRPC client to enable TLS when connecting to https://
endpoints (tonic requires explicit ClientTlsConfig).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:41:55 +01:00
jgrusewski
3bdefe86d5 feat(monitoring): production dashboards, remove Cockpit, add Kapsule logs
- Remove Cockpit remote_write from GitLab Prometheus (all metrics local)
- Uninstall k8s-monitoring Helm (Alloy no longer pushes to Cockpit)
- Deploy standalone node-exporter DaemonSet + kube-state-metrics
- Add 10 extra Prometheus scrape configs: node-exporter, kube-state-metrics,
  kubelet, cadvisor, DCGM GPU, foxhunt services, Loki, Tempo, Promtail,
  prometheus.io annotated pods
- Provision 9 Grafana dashboards via sidecar (ConfigMap-based):
  overview, services, GPU/training, infrastructure, logs, CI/CD pipelines,
  cluster overview, GPU overview, GitLab services
- Expand Promtail to ingest kube-system + GitLab runner + node-level logs
- Add dashboard.fxhnt.ai DNS record + nginx routing to Grafana
- Update CI deploy job to apply new monitoring manifests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:20:32 +01:00
jgrusewski
c731bef759 feat(infra): split training image into RL + supervised, rename ci-compile → ci-rl
RL models (DQN/PPO) only need basic CUDA runtime (~2GB), while supervised
models need cuDNN (~4GB). Splitting saves ~2GB pull time per RL job.
Rename the L4 GPU pool from ci-compile to ci-rl to reflect its actual use.
Add DaemonSet image pre-puller to cache training images on GPU nodes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:16:42 +01:00
jgrusewski
20e67d4d64 feat(ci): tune RL resources to actual usage — 2000m CPU, concurrent=2
RL env simulation is single-threaded (~1 core actual). Lowering from
7000m to 2000m request allows DQN + PPO hyperopt to run simultaneously
on one L4 node.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:46:16 +01:00
jgrusewski
6913506669 feat(ci): fix RL runner SA + full L4 node for sequential RL jobs
- Fix ServiceAccount: use serviceAccount.name (not deprecated serviceAccountName)
- concurrent=1: one RL job gets full L4 node (7000m/7800m CPU, 16Gi/40Gi RAM)
- Faster iteration: ~2.3x more CPU per job vs splitting across 2 concurrent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:28:34 +01:00
jgrusewski
0267e4949c feat(ci): add RL runner with L4 PVCs for cross-node training
- New gitlab-runner-rl Helm release: tags kapsule-rl, mounts
  training-data-l4-pvc + sccache-l4-pvc (separate RWO volumes)
- .train-rl-base now uses tags: [kapsule-rl] → picked up by RL runner
- Avoids Multi-Attach errors from RWO PVCs shared across L4/L40S nodes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:12:20 +01:00
jgrusewski
a79242466e fix(ci): nvidia RuntimeClass for all pods + correct resource overrides
- Set runtime_class_name=nvidia at runner level (all GPU pools have GPUs)
- Fix KUBERNETES_NODE_SELECTOR format: "key=value" not just value
- Replace wrong *_overwrite_allowed (regex) with correct
  *_overwrite_max_allowed (max value) for CPU/memory overrides
- Remove per-job KUBERNETES_RUNTIME_CLASS_NAME (runner-level handles it)
- Simplify GPU detection in test/compile (GPU always present now)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:43:30 +01:00
jgrusewski
0211acb682 fix(ci): increase runner default resources to prevent OOMKilled
compile-services OOMKilled at 8Gi — ml crate with CUDA needs ~20Gi.
CI variable overrides (KUBERNETES_MEMORY_LIMIT) are silently dropped
by runner config merger for non-auto-generated fields. Increase
defaults to 3500m/12Gi request, 7800m/28Gi limit to fit L4 nodes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:40:28 +01:00
jgrusewski
89a6f0d587 fix(ci): remove empty runtime_class_name from runner config
Setting runtime_class_name = "" causes Kubernetes to reject pod creation
with "resource name may not be empty". Omitting it entirely means no
runtimeClassName on pod spec by default; GPU jobs override via
KUBERNETES_RUNTIME_CLASS_NAME CI variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:16:39 +01:00
jgrusewski
46d686ee6e fix(ci): move nvidia RuntimeClass from runner default to per-job override
L4 ci-compile node was failing with 'no runtime for nvidia' because
fresh nodes take time to install nvidia drivers. Kaniko builds don't
need GPU at all. Now only Rust compile/test and training jobs request
nvidia RuntimeClass via KUBERNETES_RUNTIME_CLASS_NAME CI variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:07:35 +01:00
jgrusewski
610e0d446e perf(ci): parallelize compile+test, bump runner concurrency to 10
- compile-services now depends on check (not test), running in parallel
  with test stage — saves ~10 min from critical path
- Runner concurrent bumped 4→10 so all 9 Kaniko builds run simultaneously
- Runner default resources lowered (500m/1Gi) for lightweight Kaniko jobs;
  Rust compile/test/training override via KUBERNETES_*_REQUEST CI vars

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:50:02 +01:00