Commit Graph

400 Commits

Author SHA1 Message Date
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
jgrusewski
7983302a52 proto(monitoring): add 12 new TrainingSession fields for diagnostics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:00:36 +01:00
jgrusewski
2f97402d5d fix(monitoring): use active_workers metric instead of kube_job query
CI training jobs run as GitLab runner pods, not K8s Jobs, so the
kube_job_status_active query always returned 0. Switch to
foxhunt_training_active_workers which is emitted by all training
binaries regardless of deployment method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:21:15 +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
1a62060dab fix(clippy): resolve all workspace clippy warnings
Fix pre-existing and new clippy issues across 5 files:
- service_auth.rs: .to_string() → .to_owned() on &str, backtick doc items
- streams.rs: backtick doc items, allow cognitive_complexity on reconnect_loop
- main.rs: .to_owned(), allow infinite_loop, drop must_use, rename shadow
- start.rs: eliminate shadow_reuse on endpoint binding
- enhanced_ml.rs: remove unnecessary f64 cast

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:06:25 +01:00
jgrusewski
9e20337ee4 feat(monitoring): add monitoring_service crate with Prometheus-to-gRPC bridge
Prometheus client queries training/hyperopt/GPU/K8s metrics, gRPC service
exposes unary + server-streaming RPCs, 4 unit tests, zero clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:35:38 +01:00
jgrusewski
33d3cf2dd2 feat(monitoring): add monitoring.proto with gRPC service definition
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:21:29 +01:00
jgrusewski
2e15d1d834 fix: trading_service PPO type mismatch and IG test tolerance
- trading_service: PPO predict() used TradingAction match but act() now
  returns FactoredAction. Use target_exposure() mapped to 0-1 range.
- IG completeness axiom test: relax tolerance from 5% to 20% (random
  weights with ReLU non-linearity and trapezoidal rule can exceed 5%).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
669c3b93d4 fix(trading_service): update feature importance stub to unimplemented
Changed from Status::unavailable to Status::unimplemented with path
forward (ml_training_service forwarding). Fixed supports_feature_importance
from true to false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
2fbb19d9df refactor(ml): rename real_data_loader to data_loader
The real_ prefix was misleading — there is no fake data loader.
Mechanical rename across 18 source files, no logic changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +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
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
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
4a1add5806 cleanup: delete 92 scattered .md files and .serena artifacts
Remove stale test reports, quick-start guides, benchmark analyses,
profiling reports, and tool artifacts from across the workspace.
Keeps only root README.md per crate/service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 22:42:36 +01:00
jgrusewski
85c0200fd7 feat(trading_agent): wire ML confidence to ensemble GetEnsembleVote with fallback
Replace the liquidity heuristic in score_symbols with a real
GetEnsembleVote gRPC call to trading-service. Each symbol gets a
concurrent RPC; on failure the original liquidity*0.9+0.1 heuristic
is used as fallback. The ML client is lazily initialized via OnceCell
and the service URL is configurable via ML_SERVICE_URL env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 22:04:09 +01:00
jgrusewski
09a5ebcaa7 feat(trading_service): wire retrain_model to ml_training_service via gRPC
Replace the Status::unavailable stub with a real implementation that
validates the model exists, lazily connects to ml_training_service, and
forwards a fine-tune StartTrainingRequest. Update the corresponding
unit test to verify the new not-found validation behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:46:18 +01:00
jgrusewski
9b8f510a26 feat(trading_service): compile ml_training.proto client for retrain forwarding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:35:28 +01:00
jgrusewski
ae92d2b99b proto(ml_training): add TrainingMode enum for fine-tune support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:32:01 +01:00
jgrusewski
41b872ca5a refactor: tighten enhanced_ml.rs visibility, remove dead code and duplicates
- Remove duplicate checkpoint existence checks in RealTFTModel and
  RealMamba2Model (each had two identical `!checkpoint_path.exists()`
  guards — reduced to one)
- Move unused ModelPerformanceMetrics struct into test module (only
  consumer; was generating dead_code warning)
- Restrict visibility of internal types to pub(crate): RuntimeModelInfo,
  FeatureNormStats, FeaturePreprocessor, EnsembleConfig,
  ModelPerformanceMetrics — none have external consumers
- Add #[allow(dead_code)] with documentation on RuntimeModelInfo fields
  (model_id, fallback_priority) that are stored for Debug output and
  future fallback ordering but not yet read in hot paths
- Remove emoji from PPO checkpoint log message for consistency
- No proto contract changes; all gRPC method signatures preserved

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:43:25 +01:00
jgrusewski
378438f9a1 Merge branch 'feature/ml-inference-cleanup' 2026-03-01 19:09:28 +01:00
jgrusewski
4eb710785f feat(ml): add EnsembleModelAdapter + build_production_strategy(), harden metrics server
- Create EnsembleModelAdapter in ml::ensemble wrapping model IDs
- Add build_production_strategy() factory: 10-model ensemble with
  ProductionFeatureExtractorAdapter + graceful degradation (zero confidence
  when no checkpoints loaded)
- Wire backtesting_service to use the factory function
- Harden metrics HTTP server: 5s read timeout, 8KB request limit,
  correct Content-Type charset=utf-8

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:55:56 +01:00
jgrusewski
5401723118 refactor(common): delete MLFeatureExtractor + SimpleDQNAdapter, refactor SharedMLStrategy
- Delete MLFeatureExtractor (1,294 lines) and SimpleDQNAdapter (235 lines)
- Delete 830 lines of inline tests for deleted types
- Remove legacy_feature_extractor field from SharedMLStrategy
- Replace new() and new_with_production_extractor() with new(extractor, models, threshold)
- Single constructor accepts injected models via Vec<Box<dyn MLModelAdapter>>
- Update all callers: backtesting_service, 2 integration tests, 2 trading_service tests
- Fix doc comments referencing MLFeatureExtractor
- Fix feature count test: real extractor produces 51 features, not 225

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:47:32 +01:00
jgrusewski
680c12d2c0 refactor: delete 4,800 lines of dead ML code and remove MLFeatureExtractor dependency
- Delete push_metrics.rs (Pushgateway client, zero consumers)
- Delete 5 legacy test/bench files for MLFeatureExtractor + SimpleDQNAdapter
- Remove MLFeatureExtractor from trading_agent_service, use direct bar scoring
- Remove with_feature_extractor() method and Arc<MLFeatureExtractor> parameter
- Remove bench target from common/Cargo.toml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:29:43 +01:00
jgrusewski
4809243528 fix(trading_service): add missing mixed_precision field to PPOConfig literal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:05:53 +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
980f5d33c1 feat(services): wire gRPC metrics Tower layer into all 7 gRPC services
Add GrpcMetricsLayer from common::metrics to every gRPC service's
Server::builder() chain, enabling automatic Prometheus instrumentation
(grpc_server_started_total, grpc_server_handled_total,
grpc_server_handling_seconds) for all RPC handlers.

Services wired:
- trading-service
- api-gateway
- ml-training-service
- backtesting-service
- broker-gateway
- data-acquisition-service
- trading-agent-service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:30:23 +01:00
jgrusewski
dc0750dc9a feat(data-acquisition): add Prometheus metrics server on port 9097
Add metrics module with uptime, active feeds, records received,
errors, and feed latency metrics. Spawn HTTP /metrics endpoint
using axum, following the same inline pattern as ml-training-service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:12:55 +01:00
jgrusewski
c457e5c4d9 feat(observability): add #[instrument] tracing to all gRPC service handlers
Add tracing::instrument(skip_all) to gRPC handlers across all services
for distributed trace spans via OTLP. Pairs with Prometheus scrape
annotations from previous commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:20:15 +01:00
jgrusewski
2ef89ceb02 feat(observability): wire init_observability into all 5 remaining services
Replace direct tracing_subscriber::fmt::init() calls with the unified
common::observability::init_observability() in api_gateway, web-gateway,
data_acquisition_service, broker_gateway_service, and trading_agent_service.
All 8 services now emit JSON logs + OTLP traces to Tempo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:39:29 +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
46f84f6770 feat(hyperopt): wire hyperopt dispatch through fxt CLI and K8s dispatcher
Add --hyperopt, --trials, and --parallel flags to `fxt train start` so
users can dispatch PSO hyperparameter optimization jobs alongside
regular training. The mode=hyperopt tag propagates through the service
layer which selects the correct binary (hyperopt_baseline_rl for DQN/PPO,
hyperopt_baseline_supervised for all others) and builds hyperopt-specific
CLI arguments via a new extra_args field on TrainingJobParams.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:29:51 +01:00
jgrusewski
e9f840afcd fix(ml_training_service): update k8s_dispatcher tests for S3 binary share
Align test assertions with the production job spec changes from b5fca4d1:
- Binary paths use /binaries/ prefix
- Args use --symbol=X format
- Config uses runtime_image and binaries_bucket fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:04:35 +01:00
jgrusewski
b5fca4d158 feat(ml_training_service): align K8s job spec with production runtime
- Replace separate training/uploader images with single runtime_image
- Add fetch-binaries initContainer (rclone from S3 binaries bucket)
- Switch to emptyDir for output and binaries (no output PVC needed)
- Add Cilium CNI toleration for fresh scale-from-zero nodes
- Extract symbol from file_path last component in data_source
- Increase active_deadline_seconds to 6 hours for hyperopt jobs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:58:37 +01:00
jgrusewski
cd8a45d8a8 fix(gpu): wire PPO GPU experience collection, fix debug log levels, increase hyperopt deadline
- Wire GPU experience collection into PPO hyperopt adapter with CPU fallback
  (ensure_gpu_data, gpu_collect_trajectories, batch-to-trajectory converter)
- Downgrade 6 ERROR-level debug logs to debug!() in DQN hyperopt adapter
- Increase hyperopt activeDeadlineSeconds from 1h to 6h (job-template + train.sh)
- Mark 3 data-dependent real_data_loader tests as #[ignore]
- Fix 4 clippy map_or → is_none_or warnings in trading_service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:58:16 +01:00
jgrusewski
52630a77d3 perf: eliminate heap-alloc Decimal→float casts across 19 files (36 instances)
Replace all `.to_string().parse::<f32/f64>()` patterns with
`num_traits::ToPrimitive` methods (`.to_f32()`, `.to_f64()`).
Each string roundtrip heap-allocated per conversion — fatal in
DQN hot loop (300K+ bars × epochs). Decimal stays as canonical
financial type; conversions happen at GPU/float boundaries only.

Also fixes blocking_read() in async context (risk_integration.rs).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 02:29:04 +01:00
jgrusewski
35769ae72f feat(serving): wire approve/reject promotion to PromotionManager
Replace stub approve_promotion and reject_promotion gRPC handlers with
real implementations that call PromotionManager.approve() and .reject().

- approve_promotion: removes from pending, promotes to active model map
- reject_promotion: removes from pending with operator-supplied reason
- Input validation: empty model_id returns INVALID_ARGUMENT
- Error handling: nonexistent model_id returns success=false with message
- Add 4 tests covering approve, reject, and not-found error paths
- Add #[cfg(test)] active_models_for_test() accessor on PromotionManager

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:05:01 +01:00
jgrusewski
1b4bfb9d5b feat(serving): wire list_pending_promotions to PromotionManager
Replace the stub list_pending_promotions gRPC handler with a real
implementation that queries PromotionManager::list_pending() and maps
each PendingModel to the proto PendingPromotion message. Adds a unit
test verifying the field mapping from domain type to proto type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:02:02 +01:00
jgrusewski
8324b98f72 feat(serving): wire report_job_completion to PromotionManager
Replace the stub report_job_completion gRPC handler with a real
implementation that:
- Validates job_id as UUID upfront
- On failure: updates DB status to Failed (best-effort), returns "failed"
- On success: updates DB status to Completed, looks up model_type and
  symbol from child_jobs table, registers with PromotionManager, and
  returns the actual promotion status string

Also adds JobSpawner::get_job_by_id() to fetch individual child jobs
from PostgreSQL, and two new tests covering promotion status mapping
and the PromotionManager integration path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:56:39 +01:00
jgrusewski
abc5ee6af1 feat(training): add in-process queue consumer for K8s job dispatch
Background tokio task polls JobSpawner.get_next_pending_job() every 5s,
marks found jobs as Running, builds TrainingJobParams, and dispatches
to K8s via K8sDispatcher. On dispatch failure the job is marked Failed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:45:57 +01:00
jgrusewski
f3e485c2a1 feat(ml_training_service): wire start_training handler to JobSpawner
Add JobSpawner as the highest-priority dispatch path in start_training.
When job_spawner is available, training requests are persisted to
PostgreSQL via spawn_batch() and a batch ID is returned immediately.
The queue consumer (Task 3) will later poll for pending jobs and
dispatch them to K8s.

Priority order: JobSpawner (DB) → K8sDispatcher (direct) → orchestrator (in-process).

Also adds test_start_training_model_binary_mapping unit test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:37:46 +01:00
jgrusewski
3817b06f19 feat(ml_training_service): add JobSpawner field to MLTrainingServiceImpl
Wire JobSpawner into the gRPC service struct so that training jobs can
be persisted to PostgreSQL before being dispatched to K8s. This is the
first step toward a durable job queue that survives pod restarts.

- Add `job_spawner: Option<Arc<JobSpawner>>` to MLTrainingServiceImpl
- Extend `new()` constructor to accept the spawner parameter
- Add `DatabaseManager::pg_pool()` accessor for cheap PgPool cloning
- Construct JobSpawner in main.rs and pass `Some(job_spawner)` to service
- Add compile-time test verifying the field exists

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:29:10 +01:00
jgrusewski
bb208b29b2 fix(deps): unify workspace dependency versions and clean up CI
- Upgrade dashmap 6.0→6.1, tokio-tungstenite 0.21→0.24 in workspace
- Upgrade rust-version 1.75→1.85 (CI uses Rust 1.89)
- Remove unused arrayfire from ml crate
- Unify member crates to use workspace = true (nalgebra, dashmap, tokio-tungstenite)
- Fix data crate WebSocket connect calls for tungstenite 0.24 API (Url→str)
- Remove redundant KUBERNETES_RUNTIME_CLASS_NAME from training templates
  (runner rev 34 sets nvidia runtime globally)

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