diff --git a/docs/plans/2026-02-23-production-pipeline-wiring-design.md b/docs/plans/2026-02-23-production-pipeline-wiring-design.md new file mode 100644 index 000000000..757f4dad1 --- /dev/null +++ b/docs/plans/2026-02-23-production-pipeline-wiring-design.md @@ -0,0 +1,155 @@ +# Production Pipeline Wiring — Design + +**Date:** 2026-02-23 +**Status:** Approved +**Goal:** Connect existing components into a working end-to-end pipeline, prove it with an integration test, and validate Docker/CI infrastructure. +**Non-overlap:** Trading-universe handles data acquisition/organization. This work handles service-layer plumbing, integration testing, and infrastructure validation. + +## Problem + +The ML ensemble (10 models), conviction gates (7 gates), feature extraction (51-dim), and paper trading executor all exist and pass unit tests independently. But they are not wired together in the production service: + +1. **5 of 10 models lack inference adapters** — TGGN, TLOB, KAN, xLSTM, Diffusion have trainable adapters but no `ModelInferenceAdapter` impl for the ensemble coordinator +2. **Market data doesn't feed the ensemble** — `EnsembleCoordinator::update_market_data()` exists but nobody calls it during service startup +3. **No end-to-end test** proving the critical path works: OHLCV → features → ensemble → gates → paper trade +4. **Docker builds unvalidated** against the current 37-crate workspace +5. **CI pipelines likely stale** — 30+ workflows, many reference old structure + +## Architecture + +``` + CURRENT (disconnected) + ┌──────────┐ ┌──────────┐ ┌──────┐ ┌───────┐ + │ MarketGen │ │ Features │ │ 5/10 │ │ Paper │ + │ (exists) │ │ (exists) │ │Models │ │Trading│ + └──────────┘ └──────────┘ └──────┘ └───────┘ + ✗ not wired ✗ not fed ✗ 5 missing ✗ not connected + + TARGET (wired) + MarketGen ──→ update_market_data() ──→ 51-dim features + │ + EnsembleCoordinator (10 models) + │ + 7 Conviction Gates + │ + PaperTradingExecutor +``` + +## Task 1: Create 5 Missing Inference Adapters + +**Files:** `ml/src/ensemble/adapters/{tggn,tlob,kan,xlstm,diffusion}.rs` + +Each adapter follows the exact pattern of the existing 5 (DQN, PPO, TFT, Mamba2, Liquid): + +| Model | Adapter Name | Input | Notes | +|-------|-------------|-------|-------| +| TGGN | `TggnInferenceAdapter` | 51-dim | Graph neural network, uses adjacency matrix | +| TLOB | `TlobInferenceAdapter` | 51-dim | Transformer for limit order book | +| KAN | `KanInferenceAdapter` | 51-dim | B-spline activations | +| xLSTM | `XlstmInferenceAdapter` | 51-dim | sLSTM + mLSTM blocks, sequence buffer | +| Diffusion | `DiffusionInferenceAdapter` | 51-dim | DDPM/DDIM denoising, multi-step | + +Each implements `ModelInferenceAdapter` trait: +- `fn predict(&self, features: &FeatureVector) -> MLResult` +- `fn model_id(&self) -> &str` +- `fn model_type(&self) -> ModelType` + +Register all 5 in `ml/src/ensemble/adapters/mod.rs`. + +~100-150 lines per adapter, ~500-750 lines total. + +**Tests:** 3 tests per adapter (creation, prediction range, determinism) — same pattern as existing adapters. + +## Task 2: Register All 10 Models in main.rs + +**File:** `services/trading_service/src/main.rs` + +Add registration blocks for TGGN, TLOB, KAN, xLSTM, Diffusion following the existing pattern (match on adapter creation, wrap in `InferenceAdapterBridge`, call `register_loaded_model`). + +Initial weights (equal across 10): +| Model | Weight | +|-------|--------| +| DQN | 0.10 | +| PPO | 0.10 | +| TFT | 0.10 | +| Mamba2 | 0.10 | +| Liquid | 0.10 | +| TGGN | 0.10 | +| TLOB | 0.10 | +| KAN | 0.10 | +| xLSTM | 0.10 | +| Diffusion | 0.10 | + +~100 lines of registration code. + +## Task 3: Wire Market Data → EnsembleCoordinator + +**File:** `services/trading_service/src/main.rs` + +The test/DBN market data generators already exist as modules (`test_market_data_generator`, `dbn_market_data_generator`). Wire one as a background task that: + +1. Spawns a tokio task after ensemble coordinator initialization +2. Reads from the configured market data source (test generator for dev, DBN for staging) +3. Calls `ensemble_coordinator.update_market_data(symbol, price, volume, timestamp)` on each bar +4. Logs warmup progress (bars received vs ~51 required for feature extraction) + +~50 lines of wiring code. The generators already handle data production — this is just the connection. + +## Task 4: End-to-End Integration Test + +**File:** `services/trading_service/tests/e2e_pipeline_test.rs` + +Single `#[tokio::test(flavor = "multi_thread")]` that proves the critical path: + +1. Create `EnsembleCoordinator` with all 10 real candle adapters (untrained, random weights) +2. Feed 60 synthetic OHLCV bars via `update_market_data()` (warmup period) +3. Call `fetch_features_for_symbol()` — assert 51 real features, no NaN/Inf, no all-zeros +4. Call `predict()` — assert `EnsembleDecision` returns with: + - `action` is Buy/Sell/Hold + - `confidence` in [0.0, 1.0] + - `model_votes` has entries from all 10 models + - Conviction gate results are populated +5. Feed decision to `PaperTradingExecutor` — assert paper order generated (or HOLD from gate rejection) + +No external dependencies (no PostgreSQL, no QuestDB, no Docker). Pure in-process test. + +~150 lines. + +## Task 5: Docker Build Validation + +**Files:** All 6 Dockerfiles + `Dockerfile.foxhunt-build` + +For each service: +1. `docker build -t foxhunt-:test -f services//Dockerfile .` +2. Fix any compilation failures (missing system deps, stale paths) +3. Verify the binary starts and health check passes: `docker run --rm foxhunt-:test --help` or equivalent + +Services: +- `trading_service` (primary) +- `api_gateway` +- `ml_training_service` +- `backtesting_service` +- `trading_agent_service` +- `broker_gateway_service` + +Fix-only — no new Dockerfiles. + +## Task 6: CI Pipeline Triage + +**Directory:** `.github/workflows/` + +1. Identify the 3 essential workflows: build (`ci.yml`), test (`test.yml`), lint/clippy (`compilation-guard.yml` or `build.yml`) +2. Validate each uses `SQLX_OFFLINE=true`, correct Rust toolchain, correct workspace paths +3. Fix broken steps (missing env vars, wrong cache keys, outdated actions) +4. Delete obvious duplicates (e.g., `comprehensive-testing.yml` vs `comprehensive_testing.yml`) +5. Ensure at least build + test + clippy pass on `main` branch + +Fix-only — no new workflows. + +## Constraints + +- Build: `SQLX_OFFLINE=true cargo check --workspace` +- Test: `SQLX_OFFLINE=true cargo test -p --lib` +- Clippy: `#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::indexing_slicing)]` +- No overlap with `feat/trading-universe-data-org` branch (data acquisition, universe definition, cache structure) +- RTX 3050 Ti 4GB — adapter configs must use small hidden dims (32-64)