Commit Graph

1503 Commits

Author SHA1 Message Date
jgrusewski
f80c5bbf8a feat(ci): replace S3 upload with CI artifacts in compile-services
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:09:55 +01:00
jgrusewski
395a7c3501 feat(infra): add shared foxhunt-binaries PVC (2Gi)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:08:11 +01:00
jgrusewski
56374a43ac feat(ml): VRAM-aware hidden dimension scaling for datacenter GPUs
DQN and PPO trainers now resolve hidden_dim_base from GPU VRAM when no
explicit override is given, so L4/L40S/H100 GPUs use proportionally
larger networks instead of being stuck at RTX 3050 Ti defaults (256).

- Add resolve_hidden_dim_base() tiered lookup (256/512/768/1024 by VRAM)
- Add network_param_count() for accurate model size estimation
- DQN: pre-compute hidden dims, use real param count for batch sizing
- PPO: add hidden_dim_base field, VRAM resolution in PpoTrainer::new()
- PPO hyperopt: raise hidden_dim_base ceiling from 2048 to 4096
- TFT hyperopt: expand hidden_sizes from [128,256,512] to 5 tiers
- Update stale estimates (DQN 50K→200K, PPO 100K→400K params)
- Fix pre-existing clippy lints in prefetch.rs and ppo.rs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:02:56 +01:00
jgrusewski
d35f4e0565 docs: binary cache PVC consolidation design (8 PVCs → 1 shared)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:58:33 +01:00
jgrusewski
c86743f7eb infra: rename services → foxhunt pool in all K8s manifests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:50:44 +01:00
jgrusewski
d6d8054759 infra: migrate MinIO to platform pool with data migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:49 +01:00
jgrusewski
b3cc52c13a infra: migrate QuestDB to platform pool (fresh start)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:22:57 +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
a9edd4c0b3 infra: move monitoring stack (loki, tempo, kube-state-metrics, pushgateway) to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:08:28 +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
70672f9878 infra: move Redis to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:07:58 +01:00
jgrusewski
58f8478320 infra(tf): add platform pool, rename services → foxhunt in Kapsule module
Terraform changes for 3-pool node split:
- New `platform` pool resource (DEV1-L, databases + monitoring)
- Renamed `services` → `foxhunt` pool (DEV1-L, max_size 1)
- Updated variables, outputs, and live terragrunt inputs
- Updated implementation plan with Terraform-based workflow

Apply in 2 phases:
  Phase 1: terragrunt apply -target=scaleway_k8s_pool.platform
  Phase 2: terragrunt apply (after databases migrated to platform)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:59:21 +01:00
jgrusewski
9942ba8c29 docs: 3-pool node split implementation plan
11-task step-by-step plan: create platform pool, move monitoring
(stateless), migrate databases (PVC migration with backups), scale
services pool to 1 node. Includes verification and rollback procedures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:54:28 +01:00
jgrusewski
4da3a16bfe docs: 3-pool node split design (gitlab/platform/foxhunt)
Isolate platform infra (postgres, redis, minio, monitoring) from foxhunt
app services on separate DEV1-L nodes. Same EUR 61/mo total cost, better
blast radius containment and burst headroom for trading services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:49:46 +01:00
jgrusewski
d87c1cf21f feat(grafana): replace GPU gauges with timeseries, add CPU/Memory side-by-side
Infrastructure Cockpit:
- GPU gauges → side-by-side timeseries (GPU Utilization + GPU VRAM with total line)
- Added Memory by Service timeseries next to existing CPU by Service
- Cluster resource gauges shrunk to h=4 for tighter layout

Training Cockpit:
- GPU Utilization/Memory gauges → side-by-side timeseries matching infra cockpit
- GPU Temperature/Power widened from w=6 to w=12 in paired row

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:04:24 +01:00
jgrusewski
d8a1fa8a42 fix(grafana): show 'Inactive' instead of red on Trading Cockpit when not trading
6 stat panels (Ensemble Agreement, Prediction Confidence, Model Accuracy,
Ensemble Sharpe, Realized PnL, Unrealized PnL) showed red when ML metrics
don't exist yet. Added special null mapping → "Inactive" in dark-blue.
Panels will still show red/yellow/green when the trading system is active
and emitting metrics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:40:40 +01:00
jgrusewski
d6c65f69bd fix(grafana): fix CI dashboard showing red when idle
The "Active CI Jobs" stat panel used sum(gitlab_ci_active_jobs_sum) which
is a histogram accumulator that only grows (was showing 982 red). Changed
to sum(increase(pipeline_processing_events_total[1h])) which shows actual
pipeline activity in the last hour. Threshold changed to blue=idle,
green=active.

Also fixed Grafana provisioning:
- Removed overlapping named providers (cockpits/operations/infrastructure/cicd)
  that duplicated sidecarProvider, causing UID conflicts and write lockout
- Enabled foldersFromFilesStructure on sidecarProvider
- Unlabeled grafana-dashboards-foxhunt ConfigMap (duplicate of cockpits+operations)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:27:53 +01:00
jgrusewski
5c0d13cad2 fix(ci): route training jobs to RL runner and add OTLP tracing
- Change training job tags from kapsule to kapsule-rl so they are
  picked up exclusively by the RL runner (GPU-dedicated), not the
  general runner (CPU compile pool).
- Add OTEL_EXPORTER_OTLP_ENDPOINT to both .train-rl-base and
  .train-validate-base so training binaries export OTLP traces
  to Tempo.
- Update allow-monitoring-scrape NetworkPolicy to include
  foxhunt-ci pods so CI training pods can reach Tempo:4317.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:26:22 +01:00
jgrusewski
2651f276f4 fix(k8s): allow CI pods to access MinIO via NetworkPolicy
CI build pods have label app.kubernetes.io/part-of=foxhunt-ci,
not foxhunt. Add foxhunt-ci to the MinIO NetworkPolicy ingress
values so compile/upload jobs can reach MinIO S3 endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:01:40 +01:00
jgrusewski
090cc8b537 feat(grafana): add Platform Services row to Infrastructure Cockpit
Adds 12 stat panels in a new row between Service Status and Resources:
- Infrastructure: postgres, redis, minio, questdb (UP/DOWN)
- GitLab: webservice status + link to gitlab-services dashboard
- Network: tailscale proxy
- Monitoring: grafana, loki, tempo, kube-state-metrics (UP/DOWN)
- Counts: CI runners (active), collectors (promtail + node-exporter)

Uses w=4 panels (6 per row) for better readability on small screens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:57:53 +01:00
jgrusewski
3c09874ffa feat(grafana): add Platform Services row to infrastructure dashboard
New row shows GitLab, CI Runners, Monitoring, Collectors, Tailscale,
and Platform Total stat panels, plus a pod status table, CPU/memory
timeseries, and container restart chart for all non-foxhunt pods.

Also fix minio-init-buckets job: remove part-of:foxhunt label (triggers
default-deny egress block) and rely on minio NetworkPolicy ingress
allowlist for minio-init pods instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:42:51 +01:00
jgrusewski
d7051055f7 fix(k8s): allow minio-init job pods to reach minio via NetworkPolicy
The minio-init-buckets job pod has label app.kubernetes.io/name: minio-init
which doesn't match part-of: foxhunt (adding part-of would trigger
default-deny egress). Add explicit ingress allowlist entry for minio-init
pods on the minio NetworkPolicy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:33:39 +01:00
jgrusewski
83d0f68ab3 fix(k8s): use app.kubernetes.io/name labels in NetworkPolicy egress
All per-service NetworkPolicies used bare 'app: postgres/redis/minio'
selectors but infrastructure pods use 'app.kubernetes.io/name'. This
blocked all egress to databases, causing initContainer hangs and
service connectivity failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:12:08 +01:00
jgrusewski
303e5bd830 fix(k8s): add runAsNonRoot:false to fetch-binary initContainers
Pod-level runAsNonRoot:true conflicts with initContainer runAsUser:0.
Kubernetes rejects the container. Add explicit override so the
initContainer can still run as root to fetch binaries from S3.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:06:53 +01:00
jgrusewski
bbae6b6450 fix(k8s): allow GitLab to access minio for artifact storage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:04:06 +01:00
jgrusewski
3f2306010b fix(k8s): allow GitLab Helm pods to access postgres and redis
GitLab webservice/sidekiq share the foxhunt namespace but don't have
part-of=foxhunt label. Add release=gitlab selector to postgres and
redis NetworkPolicies so GitLab can reach its database.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:02:46 +01:00
jgrusewski
e25bc8d835 fix(k8s): fix NetworkPolicy label selectors and scope default-deny
Caught during pre-apply review:
- Scope default-deny/allow-dns/allow-monitoring to pods with
  app.kubernetes.io/part-of=foxhunt (was podSelector:{} which would
  block gitlab, grafana, loki sharing the namespace)
- Fix infrastructure.yaml: use app.kubernetes.io/name instead of
  bare app label for postgres/redis/minio/questdb podSelectors
- Add app.kubernetes.io/part-of=foxhunt to all pod templates so
  default-deny and infrastructure ingress rules match correctly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:51:54 +01:00
jgrusewski
24a75a2f74 fix(ci): use writable /tmp CA bundle for non-root rclone containers
Previous fix tried appending to /etc/ssl/certs/ca-certificates.crt
which fails on non-root containers (Permission denied). Instead,
copy system CAs to /tmp/ca-bundle.crt, append MinIO CA, and set
SSL_CERT_FILE for Go's crypto/tls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:51:36 +01:00
jgrusewski
f4e2ce852b fix(ci): trust MinIO CA in system store for rclone S3 uploads
RCLONE_CA_CERT env var does not apply to rclone's S3 backend — Go's
crypto/tls reads from the system CA bundle. Append the MinIO CA cert
to /etc/ssl/certs/ca-certificates.crt before rclone commands. Fixes
compile-services, compile-training, web-dashboard, write-manifest,
and both training base templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:47:05 +01:00
jgrusewski
3a6def362f scripts: add deploy-secrets.sh for Scaleway Secrets Manager integration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:41:13 +01:00
jgrusewski
d523ec14b8 ci: add Trivy image scanning for runtime images
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:41:13 +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
8991e031f4 infra: add SecurityContext to all service deployments
Pod-level: runAsNonRoot, runAsUser/Group 1000, seccomp RuntimeDefault.
Container-level: no privilege escalation, read-only rootfs, drop ALL caps.
Exception: ib-gateway skips runAsNonRoot and readOnlyRootFilesystem.
InitContainers keep runAsUser: 0 for binary fetch.
/tmp emptyDir (50Mi) mounted for writable scratch space.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:41:13 +01:00
jgrusewski
630141436e infra: add per-service NetworkPolicy rules
Least-privilege ingress/egress for all 8 services + IB gateway +
infrastructure pods (postgres, redis, minio, questdb). Each policy
restricts which pods can communicate on which ports, limiting lateral
movement in the cluster.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:41:13 +01:00
jgrusewski
702d67588b infra: add default-deny NetworkPolicy + DNS + monitoring exemptions
Establishes zero-trust network baseline for the foxhunt namespace:
- default-deny-all: blocks all ingress/egress unless explicitly allowed
- allow-dns: permits CoreDNS (kube-system) egress on UDP/TCP 53
- allow-monitoring-scrape: allows Prometheus ingress on metrics ports
  (9091-9098) and Tempo OTLP gRPC egress on 4317

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:41:13 +01:00
jgrusewski
56a7ca4340 fix(dashboards): standardize metric names and legend labels
Training cockpit:
- Fix 4x {{model_type}} → {{model}} in legendFormat
- Fix 5x ml_training_* → foxhunt_training_* metric prefix

Trading cockpit:
- Fix 2x {{model_type}} → {{model_id}} in legendFormat
- Fix 13x ml_* → foxhunt_* metric prefix for consistency
- Fix 2x trading_agent_* → foxhunt_trading_agent_* prefix
- Fix template variable queries to use foxhunt_ prefix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:30:38 +01:00
jgrusewski
3799981321 docs: add infrastructure security hardening implementation plan
7-task plan: NetworkPolicy (default-deny + per-service), SecurityContext
(pod + container hardening), secret scoping (split foxhunt-secrets),
deploy-secrets.sh (Scaleway integration), Trivy CI scanning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:16:44 +01:00
jgrusewski
a5e0558e08 docs: add infrastructure security hardening design
Minimal hardening plan for production deployment: NetworkPolicy
(default-deny + explicit allow), SecurityContext on all pods,
secret scoping (split monolithic foxhunt-secrets), and Trivy
image scanning in CI pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:13:13 +01:00
jgrusewski
d0e8804ec3 fix(dashboard): rename eval panels from ML to financial metrics
Accuracy → Win Rate / Directional Accuracy
F1/Precision/Recall → Sharpe / Profit Factor / Return
Fix legend labels to use {{model}} instead of {{model_type}}.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
6c3e518499 feat(ml): wire Prometheus eval metrics into evaluate_supervised
Emit set_eval_metrics (directional_accuracy, sharpe, profit_factor, return)
per fold for supervised model evaluation. Start metrics server on :9094.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
6c829d59a8 feat(ml): wire Prometheus eval metrics into evaluate_baseline
Emit set_eval_metrics (win_rate, sharpe, profit_factor, return) per fold
for DQN/PPO evaluation. Start metrics server on :9094. Feeds training
cockpit Grafana dashboard eval panels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
2cc68af7d6 feat(ml): add OTLP tracing to all 6 training/eval binaries
Replace tracing_subscriber::fmt() with init_observability() which adds
JSON structured logging + optional OTLP export to Tempo. When
OTEL_EXPORTER_OTLP_ENDPOINT env var is unset, falls back to fmt-only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
e741b50932 feat(ml): wire per-fold Prometheus metrics into train_baseline_rl
Emit set_epoch, set_epoch_loss, set_validation_loss, set_iteration_seconds
after each DQN/PPO fold completes. Feeds training cockpit Grafana dashboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
6530a20456 feat(infra): add OTEL_EXPORTER_OTLP_ENDPOINT to training job template
Training binaries export OTLP traces to Tempo when this env var is set.
Traces appear in foxhunt-traces Grafana dashboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
0ac8aeee52 refactor(common): make init_observability sync with optional OTLP endpoint
Remove unnecessary async from init_observability -- body was fully sync.
Change otlp_endpoint from &str to Option<&str> -- when None, OTLP layer
is skipped (fmt-only mode). Update all 8 service callers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:03:13 +01:00
jgrusewski
2fe2e2fe8b cleanup: delete orphaned services/tests/ directory
Standalone .rs file with no Cargo.toml, not in workspace.
Cannot compile or run. 1,280 lines of dead code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 22:54:08 +01:00
jgrusewski
3df18cf539 docs: add lib.rs doc comment to training_uploader
Add //! module-level doc comment to training_uploader/src/main.rs.
The other 6 crates (backtesting, ctrader-openapi, data, ml, risk,
trading_engine) already had doc comments and were skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 22:53:11 +01:00
jgrusewski
e2a0576ef5 docs: create/update README.md for all services, CLI, and testing crates
Create 3 missing service READMEs (api_gateway, data_acquisition_service,
trading_agent_service). Create bin/fxt/README.md. Create
testing/service-integration/README.md. Update existing service and testing
READMEs to standard template. Delete 4 subdirectory READMEs from
testing/integration/ and testing/e2e/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 22:50:38 +01:00
jgrusewski
b57df47ddc docs: create/update README.md for all 17 crates
Create 8 missing READMEs (config, ctrader-openapi, market-data, ml-data,
model_loader, risk-data, trading-data, training_uploader). Update 9 existing
READMEs to standard template format.

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