Commit Graph

442 Commits

Author SHA1 Message Date
jgrusewski
7d1b0f232f refactor(ml): move core types to ml-core + dedup MLError (5a)
Move all inline type definitions from ml/src/lib.rs to ml-core:
MLError, MLResult, Trade, MarketRegime, HealthStatus, Features,
MLModel trait, ModelRegistry, ParallelExecutor, LatencyOptimizer,
TrainingMetrics, ValidationMetrics, InferenceResult, ModelMetadata.

Dedup: consolidate ConfigError{reason}/ConfigurationError(msg) into
single ConfigError(String) tuple variant (was 2 variants, 174 refs).

Cleanup: convert create_hft_* free functions to associated methods
(HFTPerformanceProfile::ultra_low_latency(), ParallelExecutor::hft()).

ml facade re-exports via `pub use ml_core::*`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:13:41 +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
09710e590f fix(ml): audit — purge all FactoredAction::from_index from DQN paths
Critical bug: all 3 DQN action selection methods (select_action,
select_action_with_confidence, select_action_inference) used
FactoredAction::from_index() which maps indices 0-4 to exposure_idx=0
(Short100) via division by 9. This is the root cause of action
diversity collapse during both training and production inference.

Fix: ExposureLevel::from_index() + OrderRouter::route_default() in all
DQN paths. Also fixes hyperopt objective thresholds (<10 → <3 for
5-action degenerate detection), stale defaults/comments, integration
test configs.

Files: dqn.rs (3 methods), trainer.rs (validation + select_action),
hyperopt/adapters/dqn.rs (thresholds), dqn_model.rs (comments),
train_baseline_rl.rs (default), reward.rs (comment),
dqn_integration.rs + ensemble_integration.rs (num_actions).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:20:58 +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
240c144dcb feat(trading-service): implement ConfigService gRPC for dashboard config page
The dashboard's Config page was returning [unimplemented] because
trading-service had no ConfigService implementation. The API gateway's
ConfigServiceProxy forwards config RPCs to trading-service which now
handles them via direct SQL against the `configuration` table.

Implements GetConfiguration, UpdateConfiguration, DeleteConfiguration,
and ListCategories. Remaining 8 RPCs return UNIMPLEMENTED until needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:53:55 +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
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
8b6588936d fix(fxt,api): wire real gRPC auth login and add api.access permission
- Replace simulated login in fxt CLI with real AuthServiceClient gRPC call
- Add auth proto to fxt build.rs compile list and lib.rs proto module
- Add api.access permission to JWT claims issued by AuthGrpcService
- Remove orphaned ci-sensor.yaml (replaced by cluster-applied version)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 01:42:10 +01:00
jgrusewski
08d070bb95 refactor: rename JWT issuer foxhunt-api-gateway → foxhunt-api, drop compat aliases
- JWT issuer now foxhunt-api across all 16 files (services, tests, config, docker-compose)
- Remove serde alias api_gateway_url from FxtConfig (no backwards compat)
- Remove api_gateway CLI alias from e2e orchestrator
- All services must deploy simultaneously for JWT validation to match

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 00:22:04 +01:00
jgrusewski
075f715fa1 refactor: replace all api_gateway/web-gateway references across codebase
- Rename test functions, variables, bench names (api_gateway → api)
- Update e2e orchestrator executable path (target/debug/api)
- Clean Grafana dashboards: remove dead web-gateway panels, fix trailing
  pipes/commas, update pod selectors
- Update metrics_validation test metric prefixes (api_gateway_ → api_)
- Fix .gitlab-ci.yml remaining path reference
- Fix FXT CLI test flag and function names
- Keep JWT issuer foxhunt-api-gateway (cross-service auth compat)
- Keep serde alias api_gateway_url (config backwards compat)

cargo check --workspace passes cleanly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 00:18:58 +01:00
jgrusewski
84877e5146 feat: add auth gRPC service + migrate dashboard from REST/WS to grpc-web
Backend (Rust):
- Create proto/auth.proto with Login and RefreshToken RPCs
- Implement AuthGrpcService in services/api with JWT issuance
- Register as unauthenticated service in main.rs (pre-auth)
- Update JWT issuer from foxhunt-api-gateway to foxhunt-api

Dashboard (TypeScript):
- Install @connectrpc/connect-web + @bufbuild/protobuf
- Generate TypeScript proto clients via buf (src/gen/)
- Create grpc.ts transport with JWT interceptor
- Rewrite all useApi hooks to typed gRPC calls
- Replace WebSocket with useGrpcStream server-streaming hooks
- Migrate all 6 pages + 6 components to grpc-web
- Delete api.ts, websocket.ts, useWebSocket.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 00:05:18 +01:00
jgrusewski
3492b61faf chore: delete services/api_gateway/ and crates/web-gateway/
Replaced by unified services/api/ with tonic-web for grpc-web browser access.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:38:49 +01:00
jgrusewski
d25c82f8f3 refactor: rename api_gateway → api across workspace, tests, and load crate
- Workspace Cargo.toml: remove web-gateway + api_gateway members, keep api
- trading_service: dep api-gateway → api, update test imports
- testing/api-gateway-load → testing/api-load (crate renamed)
- All test crates: get_api_gateway_addr → get_api_addr + variable renames

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:38:21 +01:00
jgrusewski
e50ea55064 feat: create services/api/ — unified gRPC gateway with tonic-web
Copied from api_gateway, removed REST handlers (port 8080),
added tonic-web + CORS for grpc-web browser access.
Binary renamed: api-gateway → api

Changes:
- Package name: api-gateway → api
- Deleted src/handlers/ (REST ML endpoints on port 8080)
- Added tonic-web 0.13 + tower-http CORS layer
- Server::builder().accept_http1(true) for grpc-web
- CORS_ORIGINS env var (default http://localhost:5173)
- Metrics server on port 9091 (axum) preserved
- All 95 lib tests pass, 0 clippy warnings
- Added services/api to workspace members

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:32:46 +01:00
jgrusewski
e047c1eea3 refactor: rename all service crates to kebab-case
Rename 7 service binaries from snake_case to kebab-case to match
K8s deployment names. Update Cargo.toml package/bin names, K8s
manifest S3 paths and commands, and cross-crate dependency keys.

- api_gateway → api-gateway
- trading_service → trading-service
- broker_gateway_service → broker-gateway
- ml_training_service → ml-training-service
- backtesting_service → backtesting-service
- trading_agent_service → trading-agent-service
- data_acquisition_service → data-acquisition-service

broker-gateway gets an explicit [lib] name = "broker_gateway_service"
since its new package name maps to broker_gateway (not the original
broker_gateway_service used in source code). All other services map
correctly with Rust's automatic hyphen-to-underscore conversion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:06:00 +01:00
jgrusewski
93104e8545 refactor(ml): eliminate f64↔f32 round-trips and dead deps across ML crate
Change PercentileScaler, RewardNormalizer, CompositeReward, and
PPORewardShaper public APIs from f64 to f32 — matching what callers
actually pass. Internal EMA/percentile math stays f64 for precision.

Keep data_loader SMA/EMA/MACD accumulators in f64 throughout (was
f64→f32→f64 per step), cast to f32 only at output boundary.

Remove dead _transition computation in rainbow_agent_impl and unused
bigdecimal deps from broker_gateway_service and trading_service.

2704 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:10:04 +01:00
jgrusewski
3242abf54a fix(api_gateway): install ring CryptoProvider for kube-rs TLS
kube-rs Client::try_default() uses rustls for in-cluster TLS but no
CryptoProvider was installed, causing a panic on first pod list call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:31:12 +01:00
jgrusewski
61f88d3746 fix(monitoring): real streaming metrics, staleness detection, richer TUI
- StreamSystemStatus now queries real Prometheus data (was all zeros)
- StreamAlerts returns honest unimplemented (was sending empty events)
- Training epoch shows "N" not "N/0" (max_epochs not in proto)
- GPU power shows "300W" not "300W / 0W" when limit unavailable
- Services cockpit shows error reason when service is DOWN
- System status polling detects staleness after 3 consecutive failures
- Training cockpit header shows active K8s job count

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:44:05 +01:00
jgrusewski
edfe4da2e8 refactor(proto): remove duplicate config_service.proto
config_service.proto (package foxhunt.config, 4 RPCs) was a subset of
config.proto (package config, 12 RPCs). Migrated api_gateway to implement
ConfigService from config.proto directly. Removed dead config_service()
method from fxt client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:17:44 +01:00
jgrusewski
6d37b95072 chore: add SubscribeClusterPods stub to trading_service + plan doc
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:17:41 +01:00
jgrusewski
22809ba373 feat(api_gateway): implement SubscribeClusterPods with kube crate
Add kube 3.0 + k8s-openapi 0.27 dependencies and create pods_handler.rs
that queries the Kubernetes API for pod status. Replace the UNIMPLEMENTED
stub in monitoring_handler.rs with a real streaming implementation that
polls pods every N seconds and maps them to PodInfo proto messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:08:45 +01:00
jgrusewski
8bb86a4630 feat(api_gateway): populate ServiceStatus.version from build_info
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:01:01 +01:00
jgrusewski
a714912cb6 fix(monitoring): wire cluster resources, fix Prometheus networking
- Add query_cluster_resources() for real CPU/RAM from Prometheus
- Wire into build_response() replacing hardcoded zeros
- Fix NetworkPolicy: add ports 8080/9100/9400 for KSM/node-exporter/dcgm
- Add CiliumNetworkPolicy for hostNetwork pod scraping
- Add SubscribeClusterPods stub to unblock proto addition from Task 5

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:58:12 +01:00
jgrusewski
5fe3608d92 fix(fxt,infra): production hardening — OTLP telemetry, TUI fixes, K8s infra
- Remove opentelemetry-otlp internal-logs feature (OTLP feedback loop)
- Switch trace sampling from AlwaysOn to 10% ratio-based
- Add RUST_LOG filtering (opentelemetry/h2/tonic/hyper=warn) to all 8 services
- Wire per-service latency measurement via health check → proto metadata → TUI
- Replace Vec::remove(0) with VecDeque ring buffers (O(1) vs O(n))
- Add Arc<AtomicBool> connected_sent for first-connected detection across 12 streams
- Add MAX_RECONNECT_ATTEMPTS (10) uniformly to all stream spawners
- Change kill switch/circuit breaker fields to Option types with N/A display
- Wire data_cache to real download status stream, remove dead cluster_events
- Remove ServiceData::new() hardcoded stubs, add honest placeholders
- Fix nanos_to_hms zero/negative guard, total_records semantic fix
- Fix RwLock held across yield in broker_gateway stream_account_state
- Add break after yield Err in broker/trading stream generators
- Fix connected_at advancing per tick in stream_session_status
- Tempo: replace emptyDir with 10Gi PVC, bump memory to 512Mi/2Gi
- Remove Prometheus gitlab-annotated-pods duplicate scrape job
- Wire 6 new gRPC streaming adapters (risk, trading, ml, data-acquisition)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:39:56 +01:00
jgrusewski
63eff69bb6 feat(api_gateway): add all stream adapters + monitoring streams
Gateway poll-to-stream adapters:
- broker_gateway: StreamAccountState (3s), StreamSessionStatus (5s)
- data_acquisition: StreamDownloadStatus (5s)
- risk: StreamCircuitBreakerStatus (2s), StreamRiskMetrics (3s)
- ml: StreamModelStatus (5s)
- trading: StreamPortfolioSummary (3s), StreamOrderBook (1s)
- trading_agent: StreamAgentStatus (3s)

Monitoring handler real implementations:
- stream_system_status: fan-out health checks
- stream_metrics: Prometheus query loop
- stream_alerts: empty placeholder (no alertmanager yet)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 02:17:19 +01:00
jgrusewski
671ae541c6 Merge branch 'worktree-dqn-production-hardening' — DQN/PPO production hardening 2026-03-04 01:46:00 +01:00
jgrusewski
74eba7920e fix(dqn): real confidence from softmax Q-values, read lock for concurrent inference
Added select_action_inference(&self) — pure greedy forward pass with
no exploration mutations (epsilon, noisy nets, count bonus, step counter
are all skipped). Returns (FactoredAction, f32) where confidence is
softmax probability of the selected action, clamped [0.5, 0.95].

Also added select_action_with_confidence(&mut self) for training path
with the same confidence computation.

Production wrapper now uses read lock (was write lock), enabling
concurrent predictions. Confidence is real softmax probability
instead of hardcoded 0.85.

323 trading_service tests, 15 DQN core tests, 0 clippy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:43:48 +01:00
jgrusewski
adc5353538 fix(ppo): read config from checkpoint metadata, use dynamic feature_count
PPO now reads architecture config (state_dim, num_actions, hidden_dims,
clip_epsilon, entropy_coeff, max_grad_norm) from the _metadata.json
saved alongside the actor checkpoint. Falls back to hardcoded defaults
for legacy checkpoints without metadata.

Also fixes predict() to use self.feature_count instead of hardcoded 54,
matching the DQN pattern.

323 tests, 0 clippy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:34:17 +01:00
jgrusewski
1bf752d387 fix(dqn,ppo): production inference hardening, remove legacy aliases
DQN: disable all exploration for production (warmup=0, epsilon=0,
noisy_nets=false, count_bonus=false), read feature_count from
checkpoint metadata instead of hardcoding 54, add loaded guard
and NaN check on predict output.

PPO: fix confidence formula — use act_with_log_prob() instead of
act() which returns value_estimate not log_prob, add loaded guard
and NaN check, remove WorkingPPO alias.

Liquid: add loaded flag for is_ready()/predict() guards.

Remove EgoboxOptimizer/EgoboxOptimizerBuilder backward-compat
aliases — replaced with canonical ArgminOptimizer everywhere.

323 trading_service tests, 200 hyperopt tests, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:19:02 +01:00
jgrusewski
d0c5126985 refactor(trading_service): extract model wrappers, consolidate MLService
- Extract 5 model wrappers from enhanced_ml.rs into dedicated files:
  dqn_model.rs, ppo_model.rs, tft_model.rs, mamba2_model.rs, liquid_model.rs
- Rename enhanced_ml.rs → ml.rs, EnhancedMLServiceImpl → MLService
- Drop legacy "Real" prefix: DQNModel, PPOModel, TFTModel, Mamba2Model, LiquidModel
- Delete dead ml.rs stub (was never wired in mod.rs)
- Move model tests into their respective modules with proper test helpers
- DQNModel uses clean DQN API with FactoredAction (45 actions), checkpoint-driven config
- 312 tests passing, 0 clippy warnings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:01:28 +01:00
jgrusewski
042c38fed2 fix(dqn,ppo): verification swarm round 2 — gamma^n, checkpoint config, circuit breaker
- IQN + C51 Bellman bootstrap: gamma → gamma^n for n-step returns
- DQNConfig::from_safetensors_file(): reconstruct config from checkpoint
  metadata instead of hardcoding dims/Rainbow flags in enhanced_ml.rs
- PPO update_value_only(): add circuit breaker guard (consistency with update())
- PPO eval: tensor-core alignment on hidden dims (must match PpoTrainer)
- enhanced_ml.rs: checkpoint-driven config loading with fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:40:08 +01:00
jgrusewski
748370b198 feat(api_gateway): implement monitoring system status, health check, and metrics RPCs
Replace 3 stub RPCs with real implementations:
- get_system_status: fan-out gRPC health checks to all backends, reports SystemStatus
- get_health_check: fan-out checks with response time measurement, returns HealthCheck entries
- get_metrics: queries Prometheus for requested metric names

MonitoringServiceHandler now accepts backend URLs via with_backends() builder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:38:34 +01:00
jgrusewski
b2654a1bcc feat(api_gateway): wire all proxy services into main.rs
- Read new env vars: BROKER_GATEWAY_SERVICE_URL, DATA_ACQUISITION_SERVICE_URL,
  ML_SERVICE_URL, TRADING_AGENT_SERVICE_URL
- Create lazy channels: trading channel shared by trading/risk/config proxies,
  separate channels for ML, broker, data_acq, trading_agent
- Register 7 new services on router with auth interceptor
- Update reflection service with all 6 new proto descriptors
- Add broker/data_acq/trading_agent to health check backend list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:30:32 +01:00
jgrusewski
a35ad81885 feat(api_gateway): add 6 gRPC proxy services + server codegen for all protos
Enable server codegen for trading, risk, config protos in build.rs.
Add new compile blocks for broker_gateway, data_acquisition, ml protos.
Create 6 zero-copy forwarding proxies following TradingAgentProxy pattern:
- TradingDirectProxy (trading.TradingService, 16 RPCs)
- RiskServiceProxy (risk.RiskService, 8 RPCs)
- BrokerGatewayProxy (broker_gateway.BrokerGatewayService, 7 RPCs)
- DataAcquisitionProxy (data_acquisition.DataAcquisitionService, 5 RPCs)
- MlServiceProxy (ml.MLService, 10 RPCs)
- ConfigServiceProxy (config.ConfigService, 12 RPCs)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:28:28 +01:00
jgrusewski
cdb32cd8bf fix(dqn,ppo): comprehensive verification audit fixes — 14 files, 7 agents
DQN correctness:
- N-step Bellman target uses gamma^n (was gamma^1), fixing ~2% Q-value bias
- Cash reserve enforcement actually reduces position (was warn-only)
- CVaR sort_last_dim(true) for IQN random tau ordering
- Marsaglia-Tsang gamma sampling uses normal(0,1) not uniform(0,1)
- DQNConfig::default state_dim 51→54 (51 market + 3 portfolio)

PPO correctness:
- set_learning_rate preserves trained weights (was recreating entire model)
- update_value_only() for critic pretraining (was training both networks)
- PolicyNetwork::entropy() single forward pass (was 2x GPU compute)
- LSTM entropy uses proper H=-sum(p*log(p)) (was -mean(log_probs))
- grad_norm metric set to None (was reporting policy loss as gradient norm)

Config parity (train/eval/hyperopt/enhanced_ml):
- PPO hyperopt state_dim 51→54, value_hidden_dims 3→5 layer
- enhanced_ml feature_count 16→54, PPO policy_hidden_dims [128,64,32]→[128,64]
- Eval: tensor core alignment, Rainbow from hyperopt params, warmup alignment
- GPU batch model_state_dim 51→54 (matches kernel output)

Infrastructure:
- QNetwork dropout training mode (AtomicBool toggle, was always disabled)
- reward_history Vec→VecDeque (O(1) front removal, was O(n))
- Plateau detection distinguishes worsening from plateau in log messages

2732 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:16:08 +01:00
jgrusewski
fb4df12376 Merge branch 'feature/fxt-overhaul'
fxt 2.0 overhaul: consolidated proto/, absorbed monitoring into API Gateway,
new 15-command CLI with gRPC, MCP server mode, TUI cockpit framework.

159 files changed, net -11,835 lines.
2026-03-03 23:16:45 +01:00
jgrusewski
fc0754c63f fix(dqn): production hardening — LR scheduler, urgency costs, F32 traps, atomic IO
Wire LR scheduler to actually update the Adam optimizer (was logged but
never applied). Add update_learning_rate to DQN, RegimeConditionalDQN,
and DQNAgentType so decay_factor propagates through all agent variants.

Fix train/eval parity: CLI defaults 51→54 features, 3→45 actions;
DQN eval always uses 3-layer hidden_dims; PPO eval uses 5-layer value
network matching trainer. enhanced_ml.rs hardcoded config updated from
state_dim=16/num_actions=3 to 54/45.

Fix Candle F32/BF16 traps: replace `Tensor * 0.5` (f64 literal) with
broadcast_mul(Tensor::full(0.5_f32)) in quantile_regression.rs (2x),
dqn.rs Huber loss, and IQN gamma multiplication. Prevents panics on
Ampere+ BF16 GPUs.

Add urgency_weight() multiplier to training cost model in reward.rs
and portfolio_tracker.rs — urgency dimension (Patient/Normal/Aggressive)
now affects learned value function, matching evaluate_baseline.rs.

Fix equity tracking: additive (equity += ret) → multiplicative
(equity *= 1.0 + ret) in compute_metrics. Fix total return calc.

Fix PER beta annealing: epochs*70 → epochs*1000 (~1015 actual steps
per epoch for 130k bars / batch 128).

Fix silent target network freeze: mutex lock failure now propagates
error instead of silently skipping weight update.

Make save_checkpoint atomic (write .tmp then rename). Make NormStats
write atomic with error logging instead of silent discard.

Convert EnsembleConfig::new assert! → Result<Self, MLError> with
14 call site updates. Fix hyperopt result serialization to warn
instead of silently dropping to Value::Null.

Fix clippy MSRV mismatch: clippy.toml 1.75 → 1.85 matching Cargo.toml.

2732 tests pass, 0 clippy warnings across workspace.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:04:53 +01:00
jgrusewski
609f533abc feat: implement all 15 fxt CLI commands with real gRPC calls
- 13 commands with full gRPC implementations: service, train, tune,
  model, trade, broker, agent, data, risk, config, cluster, auth, backtest
- Streaming support: train logs --follow, broker executions --follow
- --json output on every command via OutputFormat/HumanReadable
- Fix web-gateway monitoring URL default (50057 → 50051, API Gateway)
- Rewire 7 remaining build.rs to consolidated proto/ root (web-gateway,
  backtesting_service, training_uploader, 3 test crates, e2e)
- Fix web-gateway ml_training.proto new fields (mode, max_epochs, resume)
- 75 fxt tests + 139 web-gateway tests, 0 clippy warnings, workspace clean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:16:35 +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
1421c46ed4 feat: absorb monitoring service into API Gateway
Port Prometheus scraping and training metrics RPCs directly into
api_gateway, eliminating the monitoring-service backend proxy.
MonitoringServiceProxy replaced with MonitoringServiceHandler that
queries Prometheus directly for training metrics, GPU stats, and
active job counts.

Changes:
- monitoring_proxy.rs -> monitoring_handler.rs with embedded PrometheusClient
- Remove MonitoringBackendConfig and setup_monitoring_proxy from server.rs
- main.rs reads PROMETHEUS_URL + MONITORING_STREAM_INTERVAL instead of
  MONITORING_SERVICE_URL
- Remove monitoring-service from backend health check list
- Monitoring is always available (no graceful degradation needed)
- Fix fxt build.rs compile_protos type mismatch
- All 9 ported unit tests + 0 clippy warnings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:05:27 +01:00
jgrusewski
b70c6a0bd7 refactor: rewire all service build.rs to proto/ root directory
Delete per-service proto/ directories. All 7 services now compile
from the single canonical proto/ at workspace root.

- trading_service: 5 protos + ml_training client -> ../../proto/
- ml_training_service: ml_training server + fxt_trading client -> ../../proto/
- broker_gateway_service: broker_gateway -> ../../proto/
- trading_agent_service: trading_agent + ml client -> ../../proto/
- data_acquisition_service: data_acquisition -> ../../proto/
- api_gateway: 8 proto compilations -> ../../proto/
- monitoring_service: keeps local proto (3 training RPCs only, deleted in Task 5)

Added proto/fxt_trading.proto (fat-client proto, package foxhunt.tli)
separate from proto/trading.proto (backend, package trading) since the
API gateway needs both for protocol translation.

Added unimplemented stubs for merged monitoring.proto RPCs:
- trading_service: 3 training RPCs (served by monitoring_service)
- api_gateway monitoring_proxy: 13 system health RPCs (Task 4)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:34:09 +01:00
jgrusewski
ba8fb8eedd feat(ppo): wire symlog, adaptive entropy, percentile scaling into training loop
Integrate all PPO improvement modules into the core training paths:
- Symlog value predictions in compute_value_loss (MLP + LSTM)
- Adaptive entropy auto-tuning replaces fixed entropy_coeff
- Percentile P5/P95 advantage scaling for heavy-tailed returns
- DAPO clip_epsilon_high wired in all 7 PPOConfig construction sites
- Shape mismatch fix in adaptive_entropy (unsqueeze scalar)

2726 tests pass, 0 clippy errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:12:00 +01:00
jgrusewski
392655d5fb fix: add GetEpochHistory to api_gateway proxy + clippy fixes
- Implement GetEpochHistory forwarding in MonitoringServiceProxy
- Fix clippy integer suffix style (0usize → 0_usize)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:20:11 +01:00
jgrusewski
5842859d78 feat(monitoring): wire epoch financial metrics mapper + epoch history store
- Fix action distribution metric names (add epoch_ prefix)
- Implement epoch history ring buffer (50 epochs per session)
- Wire GetEpochHistory RPC with real data
- Add test for financial metric mapping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:01:04 +01:00
jgrusewski
a471c913d7 feat(proto): add epoch financial metrics + GetEpochHistory to monitoring.proto
Add 11 financial fields (sharpe, sortino, win_rate, max_drawdown,
profit_factor, total_return, avg_return, total_trades, action
distribution) to TrainingSession (fields 36-46), a new
GetEpochHistory RPC with request/response messages, and wire the
Prometheus metric mapping in the monitoring service with a
stub RPC handler for task 7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:57:27 +01:00
jgrusewski
d04b6c7023 fix(fxt,services): remove mock fallbacks and add gRPC health checks
- trade_ml.rs: Replace 3 mock data fallbacks (submit, predictions,
  performance) with proper error propagation. Commands now fail
  honestly when the API Gateway is unreachable instead of silently
  returning fake data. Mark 3 integration tests as #[ignore].

- monitoring_service: Add tonic-health with set_serving for
  MonitoringServiceServer. Enables grpc_health_probe readiness checks.

- ml_training_service: Add tonic-health with set_serving for
  MlTrainingServiceServer. Wired into both TLS and non-TLS paths.

- data_acquisition_service: Add tonic-health with set_serving for
  DataAcquisitionServiceServer.

- ml/cuda_streams: Fix pre-existing unused variable clippy warning.

All 8 services now have standard gRPC health checking enabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:14:51 +01:00
jgrusewski
8352a0a75e feat(api-gateway): add gRPC reflection descriptors and backend health state
- Add file_descriptor_set_path for all proto compilations (enables gRPC reflection)
- Add BackendHealthState and ServiceHealthEntry for structured health tracking
- Export health types from grpc module
- Fix web-gateway network policy port

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:39:30 +01:00
jgrusewski
6d24820c1f feat(api-gateway): route MonitoringService through API gateway
Swap the stale trading_service monitoring proto (10 RPCs, never
implemented) for the real monitoring_service proto (2 RPCs:
GetLiveTrainingMetrics, StreamTrainingMetrics). Add a dedicated
MonitoringServiceProxy that forwards directly to monitoring-service
on port 50057, so `fxt watch` works end-to-end through the gateway.

- build.rs: compile monitoring_service/proto/monitoring.proto with server+client
- MonitoringServiceProxy: new zero-copy proxy (unary + streaming)
- TradingServiceProxy: remove monitoring_client, stub 6 stale methods
- main.rs: MONITORING_SERVICE_URL env, optional proxy with graceful degradation
- Network policies: api-gateway↔monitoring-service egress/ingress on 50057

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:10:43 +01:00
jgrusewski
cadea0733f feat(ml_training_service): add ApproveModel/RejectModel handlers + proxy
- ml_training_service: handlers delegate to promotion_manager
- api_gateway: proxy pass-through for both new RPCs
- Proto messages added to service-side ml_training.proto

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 02:02:20 +01:00
jgrusewski
ab218121b6 feat(monitoring): wire 12 new metric→proto field mappings in group_into_sessions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:09:54 +01:00