Commit Graph

60 Commits

Author SHA1 Message Date
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
jgrusewski
1a41f9475a refactor(infra): update all manifests for pool rename (always-on→services, ci-build→ci-compile/ci-training)
All K8s nodeSelectors, CI config, runner config, monitoring docs, and
smoke tests now reference the new pool names provisioned by terragrunt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:33:34 +01:00
jgrusewski
208f6f2392 refactor(infra): rename pools — always-on→services, ci-build→ci-training
Rename Terraform resources and Scaleway pool names for clarity:
- always_on → services (runs postgres, redis, microservices)
- ci_build → ci_training (L40S for hyperopt + training jobs)

Includes:
- moved{} blocks to prevent Terraform state destroy+recreate
- Output renames + new outputs for ci-compile and ci-training pools
- node_selector_overwrite_allowed in runner config (enables per-job
  KUBERNETES_NODE_SELECTOR_* overrides for L4/L40S routing)

MIGRATION (after terragrunt apply):
1. terragrunt apply — recreates pools with new names
2. Update K8s manifests: always-on→services in nodeSelectors
   (postgres, redis, questdb, tailscale, idle-reaper, postgres-init)
3. Update .gitlab-ci.yml: ci-build→ci-training in training jobs
4. Update runner-values.yaml: default pool ci-build→ci-compile
5. helm upgrade gitlab-runner + kubectl apply changed manifests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:20:41 +01:00
jgrusewski
8fa7eb4bcf fix(infra): fix alloy-values for k8s-monitoring v1.x + gitlab prometheus OOM
- Alloy: split host/writeEndpoint, use authMode none + extraHeaders
- Alloy: disable logs/events/opencost, set dummy Loki host (chart requires it)
- Alloy: remove kube-state-metrics nodeSelector (DEV1-M 4GB too small)
- GitLab: increase prometheus memory 512Mi→1Gi (OOMKilled on WAL replay)
- GitLab: remove writeRelabelConfigs (Prom v3 rejects camelCase config)
- GitLab: add install instructions for passing secrets via --set

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:00:40 +01:00
jgrusewski
51257dbe13 feat(infra): add Cockpit metrics + NAT gateway
Workstream 1 — NAT Gateway:
- New public-gateway TF module (VPC-GW-S, masquerade, push_default_route)
- Disable public IPs on all 6 Kapsule node pools
- Terragrunt live config with kapsule dependency

Workstream 2 — Scaleway Cockpit Metrics:
- New cockpit TF module (data source, push token, Grafana user)
- Grafana Alloy k8s-monitoring Helm values (node-exporter, kube-state-metrics)
- DCGM Exporter DaemonSet for GPU metrics (affinity on nvidia.com/gpu.present)
- GitLab Prometheus remote_write to Cockpit (filtered to gitlab_/gitaly_/sidekiq_)
- Apply-order runbook (3 phases: Cockpit → GitLab → NAT)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:33:55 +01:00
jgrusewski
f13b0df6e8 feat(infra): upgrade CI to L40S + mold linker for faster builds
- Switch linker from lld to mold (~2-5x faster linking for large binaries)
  - Install mold 2.35.1 in CI builder Dockerfile
  - Update .cargo/config.toml: -fuse-ld=mold
- Upgrade CI build pool: L4-1-24G → L40S-1-48G (~2x training throughput)
  - Increase max_size from 1 to 2 (allows concurrent jobs, fixes scheduling deadlocks)
  - Update runner resource limits for L40S node (24 vCPU, 96GB)
- Update runner-values.yaml comments and .gitlab-ci.yml header

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:05:23 +01:00
jgrusewski
a6b49b909b revert: keep runner on L4 ci-build pool (CUDA 8.9)
H100 is sm_90, not compatible with existing sm_89 sccache.
Revert runner node selector and resource limits to ci-build (L4).
Training validation stage (manual DQN/TFT smoke tests) stays.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:02:25 +01:00
jgrusewski
df4ef104b7 ci: move runner to H100 pool, add training validation stage
- Runner node selector: ci-build (L4) → gpu-training (H100) for faster
  compilation (2x+ vCPUs) and native GPU training support
- Resource limits bumped: 20 vCPU / 128Gi (was 10 vCPU / 38Gi)
- New 'train' stage with manual DQN and TFT validation jobs
  (50-step smoke tests to verify CUDA + model correctness)
- Requires helm upgrade of gitlab-runner with new values

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:56:22 +01:00
jgrusewski
1833abaaaa fix(ml): make TFT VSN layers optional for zero-dim features
CUDA cannot handle linear layers with zero input dimensions.
When num_static_features=0 or num_known_features=0, the
VariableSelectionNetwork constructor creates linear(0, 0, ...)
which triggers CUDA_ERROR_INVALID_VALUE on GPU.

- Make static/future VSN and GRN encoder fields Option<T>
- Skip layer creation when feature count is 0
- Forward pass skips absent feature paths gracefully
- Trainable adapter creates empty placeholder tensors
- Add cilium CNI toleration to training job template and runner

All 103 TFT tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:46:11 +01:00
jgrusewski
c9be395f0a fix(ci): persist runner tags in config.toml template
Runner tags were only set during initial Helm registration but lost
on re-registration. Adding tag_list to the TOML config template
ensures tags survive runner pod restarts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:58:48 +01:00
jgrusewski
d936ac36be feat(infra): auto-rotate GitLab PAT monthly via K8s CronJob
Adds a CronJob that runs on the 1st of every month at 03:00 UTC:
1. Reads current PAT from K8s Secret (gitlab-pat)
2. Calls GitLab rotate API (atomic: creates new, revokes old)
3. Updates K8s Secret with new token (3 retries)
4. Prints token to logs as recovery fallback if update fails

RBAC scoped to only get/patch the gitlab-pat secret.
Runs on gitlab node pool (zero GPU cost).

Manual trigger: kubectl -n foxhunt create job <name> --from=cronjob/gitlab-pat-rotation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:01:11 +01:00
jgrusewski
7b9da53603 infra(ci): switch CI builds from H100 to L4 — 4.7x cost reduction
Create dedicated ci-build node pool (L4-1-24G, €0.75/hr) replacing
H100 (€3.50+/hr) for CI builds. H100 reserved for training only.

- Add ci-build pool to Terraform (L4-1-24G, scale-to-zero, fr-par-2)
- Update GitLab Runner to target ci-build pool with L4-sized limits
- Change CUDA_COMPUTE_CAP from 90 (H100) to 89 (L4) in CI
- Dockerfile.training keeps CUDA_COMPUTE_CAP=90 for H100 training

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:30:04 +01:00
jgrusewski
51460a3382 perf(ci): switch sccache from S3 to local block storage PVC
- Create 20Gi sccache-pvc (scw-bssd) for fast local cache hits
- Mount at /mnt/sccache in CI build pods via runner helm values
- Use SCCACHE_DIR instead of SCCACHE_BUCKET for check/test jobs
- Kaniko builds keep S3 sccache (can't mount PVCs in Kaniko)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:12:34 +01:00
jgrusewski
3bfb9611b5 fix(ci): move PVC mount to /mnt/training-data (avoids Redis /data conflict)
Redis image WORKDIR is /data and entrypoint runs chown recursively.
PVC mounted at /data/training was read-only, causing chown to fail
with exit code 1, crashing the Redis sidecar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:54:28 +01:00
jgrusewski
0f4631de78 fix(ci): mount training-data PVC and support .dbn.zst in data loader
- Mount training-data-pvc at /data/training in build pods via runner config
- Update real_data_loader to search per-symbol subdirectories (Databento layout)
- Support .dbn.zst (zstd-compressed) files alongside raw .dbn
- Add FOXHUNT_DATA_DIR env var override for CI PVC path
- Extract decode_ohlcv_bars helper (generic over reader type)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:02:55 +01:00
jgrusewski
9cd9fba859 fix(ci): use nvidia RuntimeClass instead of pod_spec for GPU access
Replace pod_spec strategic merge patch (silently not applied) with
runtime_class_name="nvidia". The nvidia RuntimeClass uses the
nvidia-container-runtime which injects GPU drivers, nvidia-smi, and
/dev/nvidia* devices into all containers automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:04:18 +01:00
jgrusewski
f3335d87bb fix(ci): wrap pod_spec GPU patch in spec.containers (Pod-level patch)
Strategic merge patches are applied to the Pod object, not PodSpec.
The patch needs {"spec":{"containers":[...]}} not {"containers":[...]}.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:55:22 +01:00
jgrusewski
be7b8bad18 fix(ci): increase poll_timeout for H100 scale-to-zero, fix build-ci-builder rules
- poll_timeout 180s→600s: H100 provisioning takes ~3-5min from scale-to-zero
- build-ci-builder: only auto-run on push with Dockerfile changes (API
  pipelines evaluate changes=true, causing unnecessary kaniko builds)
- check: add needs:[] to decouple from prepare stage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:48:49 +01:00
jgrusewski
041312acc4 fix(ci): add CUDA_COMPUTE_CAP=90 and GPU resource request for H100 builds
bindgen_cuda calls nvidia-smi to detect compute capability, which fails
without GPU device access. Setting CUDA_COMPUTE_CAP=90 bypasses this for
compilation. Pod spec GPU request ensures NVIDIA device plugin injects
/dev/nvidia* for test-time CUDA execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:08:34 +01:00
jgrusewski
10d81b0703 infra(kapsule): consolidate CI builds onto H100 gpu-training pool
Remove orphaned `ci` pool (GP1-XS, 4 vCPU wasted — nothing scheduled to it).
Remove `ci-build` pool (GP1-M) — builds now run on gpu-training (H100-1-80G:
24 vCPU, 240GB, real CUDA). This eliminates the need for CUDA stubs,
separate test-gpu jobs, and ml crate exclusions.

Pool layout after:
  always-on    DEV1-M        (core services, always on)
  gitlab       GP1-XS        (GitLab CE + runner manager, always on)
  gpu-training H100-1-80G    (CI builds + ML training, scale-to-zero)
  gpu-inference L4-1-24G     (trading inference, scale-to-zero)

Build pod limits bumped to 16 vCPU / 64GB (from 6/12GB) to use H100 capacity.
Runner now has `gpu` tag — all tests including ml crate run in single job.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:20:26 +01:00
Administrator
84f935a70e ci: CUDA CI builder image via Scaleway CR
- Push ci-builder to rg.fr-par.scw.cloud/foxhunt-ci (Kapsule nodes can pull natively)
- Add SCR + GitLab imagePullSecrets to runner config
- Dockerfile.ci-builder unchanged (CUDA 12.4 + Rust 1.89 + protoc + sccache)
2026-02-25 08:54:55 +00:00