From 092b1d2a24bdbd60a2699bb9f324955c0ebebe7d Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sat, 7 Mar 2026 21:49:36 +0100 Subject: [PATCH] docs(ml): update plan for 6-crate split (DQN/PPO separate) Split ml-rl into ml-dqn and ml-ppo for 3-way parallel compilation and better sccache hit rate. Extract TradingAction to ml-core to enable full DQN/PPO independence. Co-Authored-By: Claude Opus 4.6 --- .../plans/2026-03-07-ml-crate-split-design.md | 51 ++-- docs/plans/2026-03-07-ml-crate-split-plan.md | 243 ++++++++++++------ 2 files changed, 196 insertions(+), 98 deletions(-) diff --git a/docs/plans/2026-03-07-ml-crate-split-design.md b/docs/plans/2026-03-07-ml-crate-split-design.md index 1bb8df69a..bf0c949ec 100644 --- a/docs/plans/2026-03-07-ml-crate-split-design.md +++ b/docs/plans/2026-03-07-ml-crate-split-design.md @@ -14,7 +14,8 @@ Split `ml` into sub-crates that compile in parallel, reducing: ``` ml-core (shared types, traits, utilities, features, data) - ├─→ ml-rl (DQN + PPO + cuda_pipeline) ── parallel ──┐ + ├─→ ml-dqn (DQN + cuda_pipeline) ── parallel ──┐ + ├─→ ml-ppo (PPO) ── parallel ──┤ ├─→ ml-supervised (TFT, Mamba, Liquid, etc.) ── parallel ──┤ │ ↓ └──────────────────────────→ ml-infra (hyperopt, ensemble, trainers) @@ -22,7 +23,7 @@ ml-core (shared types, traits, utilities, features, data) ml (thin facade, re-exports) ``` -`ml-rl` and `ml-supervised` compile **fully in parallel** — they have zero dependencies on each other. +`ml-dqn`, `ml-ppo`, and `ml-supervised` compile in **3-way parallel** — they have zero dependencies on each other. This also maximizes sccache hit rate in CI: editing DQN never invalidates PPO's cache entry. ## Crate Assignment (Every Module Accounted For) @@ -78,19 +79,29 @@ Shared infrastructure that 2+ other sub-crates depend on. - `dqn/action_space.rs` (245 lines) → `ml-core/src/action_space.rs` - `dqn/order_router.rs` (175 lines) → `ml-core/src/order_router.rs` +**Extracted from dqn/agent.rs → ml-core:** +- `TradingAction` enum (Buy/Sell/Hold) — used by PPO tests, must be in ml-core for DQN/PPO independence + **NOT extracting:** - `dqn/circuit_breaker.rs` — already a re-export of `common/circuit_breaker.rs` (which stays in ml-core) - `liquid/FixedPoint` — only used by mamba (both in ml-supervised), no extraction needed -### ml-rl (~44K lines) +### ml-dqn (~35K lines) -Reinforcement learning models. Depends on: `ml-core`. +DQN reinforcement learning. Depends on: `ml-core`. + +- `dqn/` (33,116 lines minus ~2,500 extracted = ~30,600 lines) +- `cuda_pipeline/` (4,431 lines) — GPU data pipeline for DQN trainers + +### ml-ppo (~14K lines) + +PPO reinforcement learning. Depends on: `ml-core`. **Zero dependency on ml-dqn.** -- `dqn/` (33,116 lines minus 2,273 extracted = ~30,843 lines) - `ppo/` (14,182 lines) -- `cuda_pipeline/` (4,431 lines) — GPU data pipeline for DQN/PPO trainers -**Import changes:** +After extraction of shared items to ml-core, PPO's only remaining DQN import was `TradingAction` (test-only) — now in ml-core. + +### Import changes (ml-dqn and ml-ppo): - `crate::dqn::mixed_precision::training_dtype` → `ml_core::mixed_precision::training_dtype` - `crate::dqn::xavier_init::linear_xavier` → `ml_core::xavier_init::linear_xavier` - `crate::dqn::portfolio_tracker` → `ml_core::portfolio_tracker` @@ -122,7 +133,7 @@ Supervised/generative models. Depends on: `ml-core`. **Zero dependency on ml-rl. ### ml-infra (~67K lines) -Training infrastructure. Depends on: `ml-core`, `ml-rl`, `ml-supervised`. +Training infrastructure. Depends on: `ml-core`, `ml-dqn`, `ml-ppo`, `ml-supervised`. - `hyperopt/` (19,934 lines) — Bayesian optimization, adapters for all 10 models - `ensemble/` (13,744 lines) — inference adapters, confidence, voting @@ -133,8 +144,8 @@ Training infrastructure. Depends on: `ml-core`, `ml-rl`, `ml-supervised`. - `walk_forward.rs` (485 lines) **Import changes:** -- `crate::dqn::DQN` → `ml_rl::dqn::DQN` -- `crate::ppo::PPO` → `ml_rl::ppo::PPO` +- `crate::dqn::DQN` → `ml_dqn::dqn::DQN` +- `crate::ppo::PPO` → `ml_ppo::ppo::PPO` - `crate::tft::TemporalFusionTransformer` → `ml_supervised::tft::TemporalFusionTransformer` - (and so on for all model types) - Shared items: `crate::X` → `ml_core::X` @@ -173,11 +184,11 @@ Re-exports everything from sub-crates. Contains modules that cross sub-crate bou **Re-exports (preserves external API):** ```rust // ml/src/lib.rs -pub use ml_core::*; // All types, errors, traits -pub use ml_rl::dqn; // DQN module -pub use ml_rl::ppo; // PPO module -pub use ml_rl::cuda_pipeline; // GPU pipeline -pub use ml_supervised::tft; // All supervised models +pub use ml_core::*; // All types, errors, traits +pub use ml_dqn::dqn; // DQN module +pub use ml_dqn::cuda_pipeline; // GPU pipeline +pub use ml_ppo::ppo; // PPO module +pub use ml_supervised::tft; // All supervised models pub use ml_supervised::mamba; // ... etc for all model modules pub use ml_infra::hyperopt; @@ -198,7 +209,7 @@ pub use ml_infra::trainers; | `mimalloc-allocator` | `ml-core` | allocator | | `simd` | `ml-core` | SIMD features | | `gc` | `ml-core` | GC features | -| `nccl` | `ml-rl` | multi-GPU for RL training | +| `nccl` | `ml-dqn` | multi-GPU for RL training | ## External Consumer Migration @@ -209,13 +220,15 @@ All external consumers (`trading_service`, `ml_training_service`, etc.) continue | Phase | Time | Parallelism | |-------|------|-------------| | ml-core | ~15s | serial (first) | -| ml-rl + ml-supervised | ~13s | **2-way parallel** | +| ml-dqn + ml-ppo + ml-supervised | ~12s | **3-way parallel** | | ml-infra | ~18s | serial (after models) | | ml facade | ~3s | serial (last) | -| **Total clean** | **~49s** | vs 55s current | -| **Edit in dqn (incremental)** | **~13s** | vs 55s current | +| **Total clean** | **~48s** | vs 55s current | +| **Edit in dqn (incremental)** | **~12s** | vs 55s current | +| **Edit in ppo (incremental)** | **~6s** | vs 55s current | | **Edit in tft (incremental)** | **~10s** | vs 55s current | | **Edit in features (incremental)** | **~10s** | vs 55s current | +| **CI sccache (PPO edit)** | **~6s** | only ml-ppo rebuilt | ## Risks diff --git a/docs/plans/2026-03-07-ml-crate-split-plan.md b/docs/plans/2026-03-07-ml-crate-split-plan.md index 096592d71..ba5f788e8 100644 --- a/docs/plans/2026-03-07-ml-crate-split-plan.md +++ b/docs/plans/2026-03-07-ml-crate-split-plan.md @@ -2,9 +2,9 @@ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. -**Goal:** Split the monolithic `ml` crate (260K lines, 55s compile) into 5 crates that compile in parallel, reducing incremental rebuilds from 55s to ~10-15s. +**Goal:** Split the monolithic `ml` crate (260K lines, 55s compile) into 6 crates that compile in parallel, reducing incremental rebuilds from 55s to ~6-12s. -**Architecture:** 4 sub-crates (`ml-core`, `ml-rl`, `ml-supervised`, `ml-infra`) + thin `ml` facade that re-exports everything. External consumers see no API changes. +**Architecture:** 5 sub-crates (`ml-core`, `ml-dqn`, `ml-ppo`, `ml-supervised`, `ml-infra`) + thin `ml` facade. DQN, PPO, and supervised models compile in 3-way parallel. External consumers see no API changes. **Tech Stack:** Rust workspace, Cargo features, `pub use` re-exports. @@ -39,8 +39,10 @@ Note the exact test count and build time for comparison after split. **Files:** - Create: `crates/ml-core/Cargo.toml` - Create: `crates/ml-core/src/lib.rs` -- Create: `crates/ml-rl/Cargo.toml` -- Create: `crates/ml-rl/src/lib.rs` +- Create: `crates/ml-dqn/Cargo.toml` +- Create: `crates/ml-dqn/src/lib.rs` +- Create: `crates/ml-ppo/Cargo.toml` +- Create: `crates/ml-ppo/src/lib.rs` - Create: `crates/ml-supervised/Cargo.toml` - Create: `crates/ml-supervised/src/lib.rs` - Create: `crates/ml-infra/Cargo.toml` @@ -50,7 +52,7 @@ Note the exact test count and build time for comparison after split. **Step 1: Create crate directories** ```bash -mkdir -p crates/ml-core/src crates/ml-rl/src crates/ml-supervised/src crates/ml-infra/src +mkdir -p crates/ml-core/src crates/ml-dqn/src crates/ml-ppo/src crates/ml-supervised/src crates/ml-infra/src ``` **Step 2: Add workspace members** @@ -58,7 +60,8 @@ mkdir -p crates/ml-core/src crates/ml-rl/src crates/ml-supervised/src crates/ml- In root `Cargo.toml`, add to `[workspace] members`: ```toml "crates/ml-core", -"crates/ml-rl", +"crates/ml-dqn", +"crates/ml-ppo", "crates/ml-supervised", "crates/ml-infra", ``` @@ -66,7 +69,8 @@ In root `Cargo.toml`, add to `[workspace] members`: And add workspace dependency entries: ```toml ml-core = { path = "crates/ml-core" } -ml-rl = { path = "crates/ml-rl" } +ml-dqn = { path = "crates/ml-dqn" } +ml-ppo = { path = "crates/ml-ppo" } ml-supervised = { path = "crates/ml-supervised" } ml-infra = { path = "crates/ml-infra" } ``` @@ -77,9 +81,9 @@ Each sub-crate gets a `Cargo.toml` with: - Same edition/rust-version as `ml` - Dependencies subset (only what its modules need) - Feature flags relevant to its modules -- `ml-core` as dependency for `ml-rl`, `ml-supervised`, `ml-infra` +- `ml-core` as dependency for `ml-dqn`, `ml-ppo`, `ml-supervised`, `ml-infra` -See the detailed Cargo.toml specs in Tasks 5-8. +See the detailed Cargo.toml specs in Tasks 4-10. **Step 4: Create stub lib.rs for each** @@ -97,7 +101,7 @@ Expected: Compiles (empty crates are valid) **Step 6: Commit** ```bash -git add crates/ml-core crates/ml-rl crates/ml-supervised crates/ml-infra Cargo.toml +git add crates/ml-core crates/ml-dqn crates/ml-ppo crates/ml-supervised crates/ml-infra Cargo.toml git commit -m "feat(ml): scaffold sub-crate directory structure for ml split" ``` @@ -107,7 +111,7 @@ git commit -m "feat(ml): scaffold sub-crate directory structure for ml split" ### Task 3: Extract Shared Items from dqn/ to Top-Level Modules -These items live in `dqn/` but are used by PPO, trainers, ensemble, hyperopt — they belong in `ml-core`. +These items live in `dqn/` but are used by PPO, trainers, ensemble, hyperopt — they belong in `ml-core`. Also extract `TradingAction` from `dqn/agent.rs` to enable DQN/PPO independence. **Files:** - Move: `crates/ml/src/dqn/mixed_precision.rs` → `crates/ml/src/mixed_precision.rs` @@ -115,6 +119,8 @@ These items live in `dqn/` but are used by PPO, trainers, ensemble, hyperopt — - Move: `crates/ml/src/dqn/portfolio_tracker.rs` → `crates/ml/src/portfolio_tracker.rs` - Move: `crates/ml/src/dqn/action_space.rs` → `crates/ml/src/action_space.rs` - Move: `crates/ml/src/dqn/order_router.rs` → `crates/ml/src/order_router.rs` +- Modify: `crates/ml/src/dqn/agent.rs` — move `TradingAction` enum to new file +- Create: `crates/ml/src/trading_action.rs` — `TradingAction` enum (Buy/Sell/Hold) - Modify: `crates/ml/src/dqn/mod.rs` — replace module declarations with re-exports - Modify: `crates/ml/src/lib.rs` — add `pub mod` for new top-level modules - Modify: All files importing these via `crate::dqn::*` path @@ -130,7 +136,11 @@ mv dqn/action_space.rs action_space.rs mv dqn/order_router.rs order_router.rs ``` -**Step 2: Update dqn/mod.rs** +**Step 2: Extract TradingAction from dqn/agent.rs** + +Create `crates/ml/src/trading_action.rs` with the `TradingAction` enum (copied from `dqn/agent.rs`). In `dqn/agent.rs`, replace the enum with `pub use crate::trading_action::TradingAction;`. This is the only PPO→DQN dependency remaining after the other extractions — making it shared enables full DQN/PPO independence. + +**Step 3: Update dqn/mod.rs** Replace the old `pub mod` declarations with re-exports so existing `crate::dqn::X` paths still work: ```rust @@ -146,9 +156,10 @@ pub use crate::xavier_init; pub use crate::portfolio_tracker; pub use crate::action_space; pub use crate::order_router; +pub use crate::trading_action::TradingAction; ``` -**Step 3: Add modules to ml/lib.rs** +**Step 4: Add modules to ml/lib.rs** Add these lines to `lib.rs`: ```rust @@ -157,11 +168,12 @@ pub mod xavier_init; pub mod portfolio_tracker; pub mod action_space; pub mod order_router; +pub mod trading_action; ``` -**Step 4: Fix internal imports in moved files** +**Step 5: Fix internal imports in moved files** -In each moved file, change `use crate::dqn::` imports to `use crate::` where referencing peer modules (e.g., `mixed_precision.rs` may import from `dqn` internals — fix those paths). +In each moved file, change `use crate::dqn::` imports to `use crate::` where referencing peer modules. Specific fixes needed: - `action_space.rs`: has no `crate::dqn::` imports (only std/serde) — no changes needed @@ -169,6 +181,7 @@ Specific fixes needed: - `mixed_precision.rs`: uses `candle_core` only — no changes needed - `portfolio_tracker.rs`: check for `crate::dqn::` imports and fix - `order_router.rs`: imports `crate::dqn::action_space::*` → change to `crate::action_space::*`; imports `crate::common::action::*` → keep as-is +- PPO test files using `crate::dqn::TradingAction` → change to `crate::trading_action::TradingAction` **Step 5: Verify compilation** @@ -383,16 +396,16 @@ Re-export from ml facade for backward compatibility." --- -## Phase 3: Build ml-rl (RL Models) +## Phase 3: Build ml-dqn and ml-ppo (RL Models — Separate Crates) -### Task 6: Write ml-rl Cargo.toml +### Task 6: Write ml-dqn Cargo.toml **Files:** -- Create: `crates/ml-rl/Cargo.toml` +- Create: `crates/ml-dqn/Cargo.toml` **Step 1: Write Cargo.toml** -Dependencies: `ml-core` + `candle-core`, `candle-nn` + RL-specific deps (`crossbeam`, etc.). +Dependencies: `ml-core` + `candle-core`, `candle-nn` + DQN-specific deps (`crossbeam`, etc.). Feature flags: ```toml @@ -406,41 +419,39 @@ nccl = ["cuda"] --- -### Task 7: Move RL Modules to ml-rl +### Task 7a: Move DQN + cuda_pipeline to ml-dqn **Files:** -- Move: `crates/ml/src/dqn/` → `crates/ml-rl/src/dqn/` -- Move: `crates/ml/src/ppo/` → `crates/ml-rl/src/ppo/` -- Move: `crates/ml/src/cuda_pipeline/` → `crates/ml-rl/src/cuda_pipeline/` -- Modify: `crates/ml-rl/src/lib.rs` +- Move: `crates/ml/src/dqn/` → `crates/ml-dqn/src/dqn/` +- Move: `crates/ml/src/cuda_pipeline/` → `crates/ml-dqn/src/cuda_pipeline/` +- Modify: `crates/ml-dqn/src/lib.rs` - Modify: `crates/ml/src/lib.rs` **Step 1: Move modules** ```bash -mv crates/ml/src/dqn crates/ml-rl/src/ -mv crates/ml/src/ppo crates/ml-rl/src/ -mv crates/ml/src/cuda_pipeline crates/ml-rl/src/ +mv crates/ml/src/dqn crates/ml-dqn/src/ +mv crates/ml/src/cuda_pipeline crates/ml-dqn/src/ ``` -**Step 2: Write ml-rl/src/lib.rs** +**Step 2: Write ml-dqn/src/lib.rs** ```rust // Same clippy attributes as ml-core pub mod dqn; -pub mod ppo; pub mod cuda_pipeline; ``` -**Step 3: Fix all imports in ml-rl** +**Step 3: Fix all imports in ml-dqn** -In every file under `crates/ml-rl/src/`: +In every file under `crates/ml-dqn/src/`: - `use crate::MLError` → `use ml_core::MLError` - `use crate::mixed_precision` → `use ml_core::mixed_precision` - `use crate::xavier_init` → `use ml_core::xavier_init` - `use crate::portfolio_tracker` → `use ml_core::portfolio_tracker` - `use crate::action_space` → `use ml_core::action_space` - `use crate::order_router` → `use ml_core::order_router` +- `use crate::trading_action` → `use ml_core::trading_action` - `use crate::common::` → `use ml_core::common::` - `use crate::cuda_compat::` → `use ml_core::cuda_compat::` - `use crate::gradient_accumulation::` → `use ml_core::gradient_accumulation::` @@ -455,57 +466,42 @@ In every file under `crates/ml-rl/src/`: - `use crate::PRECISION_FACTOR` → `use ml_core::PRECISION_FACTOR` - `use crate::{MLError, MLResult}` → `use ml_core::{MLError, MLResult}` -Keep `use crate::dqn::` and `use crate::ppo::` as-is (these reference ml-rl's own modules). +Keep `use crate::dqn::` as-is (references ml-dqn's own dqn module). +Keep `use crate::cuda_pipeline::` as-is (references ml-dqn's own cuda_pipeline module). -Remove the re-exports from `dqn/mod.rs` added in Task 3 (they re-exported from `crate::` which was ml, now those modules are in ml-core): +Update the re-exports from `dqn/mod.rs` added in Task 3: ```rust -// REMOVE these from dqn/mod.rs: -// pub use crate::mixed_precision; -// pub use crate::xavier_init; -// etc. -// REPLACE WITH: +// REPLACE crate:: references WITH ml_core:: pub use ml_core::mixed_precision; pub use ml_core::xavier_init; pub use ml_core::portfolio_tracker; pub use ml_core::action_space; pub use ml_core::order_router; +pub use ml_core::trading_action::TradingAction; ``` -Also fix PPO re-exports in `ppo/mod.rs`: -```rust -// ppo/circuit_breaker.rs re-exports from crate::common::circuit_breaker -// Change to: ml_core::common::circuit_breaker -``` +cuda_pipeline imports: +- `crate::dqn::mixed_precision` → `ml_core::mixed_precision` +- `crate::dqn::replay_buffer_type::GpuBatch` → `crate::dqn::replay_buffer_type::GpuBatch` (stays in ml-dqn ✓) -Handle cross-RL deps: -- PPO imports `crate::dqn::circuit_breaker` → becomes `crate::dqn::circuit_breaker` (still works via dqn re-export) OR `ml_core::common::circuit_breaker` (direct) -- PPO imports `crate::dqn::mixed_precision::training_dtype` → `ml_core::mixed_precision::training_dtype` -- PPO imports `crate::dqn::portfolio_tracker` → `ml_core::portfolio_tracker` -- PPO imports `crate::dqn::xavier_init::linear_xavier` → `ml_core::xavier_init::linear_xavier` -- cuda_pipeline imports `crate::dqn::mixed_precision` → `ml_core::mixed_precision` -- cuda_pipeline imports `crate::dqn::replay_buffer_type::GpuBatch` → `crate::dqn::replay_buffer_type::GpuBatch` (stays in ml-rl) - -Watch for: `use crate::trainers::DQNTrainer` in dqn/ — this is a reverse dep. If it exists, it's likely in test code. If in non-test code, it needs to be removed/refactored (trainers will be in ml-infra). - -Watch for: `use crate::hyperopt::adapters::PPOTrainer` in ppo/ — same issue. Check if test-only. +Watch for: `use crate::trainers::DQNTrainer` in dqn/ — reverse dep, likely test-only. Remove or cfg(test) gate with a comment. **Step 4: Update ml/src/lib.rs** Add re-exports: ```rust -pub use ml_rl::dqn; -pub use ml_rl::ppo; -pub use ml_rl::cuda_pipeline; +pub use ml_dqn::dqn; +pub use ml_dqn::cuda_pipeline; ``` Add dependency to `ml/Cargo.toml`: ```toml -ml-rl = { workspace = true } +ml-dqn = { workspace = true } ``` **Step 5: Verify compilation** -Run: `SQLX_OFFLINE=true cargo check -p ml-rl 2>&1 | tail -10` +Run: `SQLX_OFFLINE=true cargo check -p ml-dqn 2>&1 | tail -10` Run: `SQLX_OFFLINE=true cargo check -p ml 2>&1 | tail -10` **Step 6: Fix errors iteratively** @@ -520,7 +516,89 @@ Run: `SQLX_OFFLINE=true cargo test -p ml --lib 2>&1 | tail -5` ```bash git add -A -git commit -m "refactor(ml): move DQN, PPO, cuda_pipeline to ml-rl crate" +git commit -m "refactor(ml): move DQN + cuda_pipeline to ml-dqn crate" +``` + +--- + +### Task 7b: Write ml-ppo Cargo.toml and Move PPO + +**Files:** +- Create: `crates/ml-ppo/Cargo.toml` +- Move: `crates/ml/src/ppo/` → `crates/ml-ppo/src/ppo/` +- Modify: `crates/ml-ppo/src/lib.rs` +- Modify: `crates/ml/src/lib.rs` + +**Step 1: Write ml-ppo Cargo.toml** + +Dependencies: `ml-core` + `candle-core`, `candle-nn`. NO dependency on `ml-dqn`. + +Feature flags: +```toml +[features] +default = ["cuda"] +cuda = ["ml-core/cuda"] +``` + +**Step 2: Move PPO** + +```bash +mv crates/ml/src/ppo crates/ml-ppo/src/ +``` + +**Step 3: Write ml-ppo/src/lib.rs** + +```rust +// Same clippy attributes as ml-core +pub mod ppo; +``` + +**Step 4: Fix all imports in ml-ppo** + +Same pattern as ml-dqn: `use crate::X` → `use ml_core::X` for all shared items. + +Key changes: +- `use crate::dqn::circuit_breaker` → `use ml_core::common::circuit_breaker` (direct path, no dqn dependency) +- `use crate::dqn::mixed_precision::training_dtype` → `use ml_core::mixed_precision::training_dtype` +- `use crate::dqn::portfolio_tracker` → `use ml_core::portfolio_tracker` +- `use crate::dqn::xavier_init::linear_xavier` → `use ml_core::xavier_init::linear_xavier` +- `use crate::dqn::TradingAction` → `use ml_core::trading_action::TradingAction` (test-only) + +Fix `ppo/circuit_breaker.rs`: +```rust +// Change: pub use crate::common::circuit_breaker::* +// To: pub use ml_core::common::circuit_breaker::* +``` + +Watch for: `use crate::hyperopt::adapters::PPOTrainer` in ppo/ — reverse dep, likely test-only. + +**Step 5: Update ml/src/lib.rs** + +```rust +pub use ml_ppo::ppo; +``` + +Add dependency: `ml-ppo = { workspace = true }` + +**Step 6: Verify compilation** + +Run: `SQLX_OFFLINE=true cargo check -p ml-ppo 2>&1 | tail -10` +Run: `SQLX_OFFLINE=true cargo check -p ml 2>&1 | tail -10` + +**Step 7: Verify DQN and PPO are independent** + +Run: `SQLX_OFFLINE=true cargo tree -p ml-ppo --depth 1 | grep ml-dqn` +Expected: NO output (ml-ppo must NOT depend on ml-dqn) + +**Step 8: Run tests** + +Run: `SQLX_OFFLINE=true cargo test -p ml --lib 2>&1 | tail -5` + +**Step 9: Commit** + +```bash +git add -A +git commit -m "refactor(ml): move PPO to ml-ppo crate (independent of ml-dqn)" ``` --- @@ -642,13 +720,13 @@ transformers and flash_attention infrastructure." **Files:** - Create: `crates/ml-infra/Cargo.toml` -Dependencies: `ml-core`, `ml-rl`, `ml-supervised` + `argmin` (for hyperopt), model-specific deps. +Dependencies: `ml-core`, `ml-dqn`, `ml-ppo`, `ml-supervised` + `argmin` (for hyperopt), model-specific deps. Feature flags: ```toml [features] default = ["cuda"] -cuda = ["ml-core/cuda", "ml-rl/cuda", "ml-supervised/cuda"] +cuda = ["ml-core/cuda", "ml-dqn/cuda", "ml-ppo/cuda", "ml-supervised/cuda"] ``` **Step 1: Commit** @@ -692,10 +770,11 @@ pub mod walk_forward; **Step 3: Fix all imports** -This is the most complex crate — it imports from all three sub-crates: -- `use crate::dqn::DQN` → `use ml_rl::dqn::DQN` -- `use crate::dqn::DQNConfig` → `use ml_rl::dqn::DQNConfig` -- `use crate::ppo::PPO` → `use ml_rl::ppo::PPO` +This is the most complex crate — it imports from all four model sub-crates: +- `use crate::dqn::DQN` → `use ml_dqn::dqn::DQN` +- `use crate::dqn::DQNConfig` → `use ml_dqn::dqn::DQNConfig` +- `use crate::ppo::PPO` → `use ml_ppo::ppo::PPO` +- `use crate::cuda_pipeline::*` → `use ml_dqn::cuda_pipeline::*` - `use crate::tft::*` → `use ml_supervised::tft::*` - `use crate::mamba::*` → `use ml_supervised::mamba::*` - `use crate::liquid::*` → `use ml_supervised::liquid::*` @@ -704,7 +783,6 @@ This is the most complex crate — it imports from all three sub-crates: - `use crate::xlstm::*` → `use ml_supervised::xlstm::*` - `use crate::tgnn::*` → `use ml_supervised::tgnn::*` - `use crate::tlob::*` → `use ml_supervised::tlob::*` -- `use crate::cuda_pipeline::*` → `use ml_rl::cuda_pipeline::*` - All shared items: `use crate::X` → `use ml_core::X` **Step 4: Update ml/src/lib.rs** @@ -749,7 +827,7 @@ git commit -m "refactor(ml): move hyperopt, ensemble, trainers to ml-infra crate **Step 1: Update ml/Cargo.toml** -- Add: `ml-core`, `ml-rl`, `ml-supervised`, `ml-infra` as dependencies +- Add: `ml-core`, `ml-dqn`, `ml-ppo`, `ml-supervised`, `ml-infra` as dependencies - Remove: all dependencies that are now only used by sub-crates - Keep: dependencies used by remaining facade modules (`inference.rs`, `validation/`, `risk/`, etc.) @@ -760,7 +838,8 @@ Every module path that external consumers use (e.g., `ml::dqn::DQNConfig`, `ml:: **Step 3: Fix remaining facade module imports** Modules still in ml facade (`inference.rs`, `validation/`, `risk/`, `regime/`, etc.) need import updates: -- `use crate::dqn::` — these now come from `ml_rl` via re-export, so `use crate::dqn::` still works ✓ +- `use crate::dqn::` — these now come from `ml_dqn` via re-export, so `use crate::dqn::` still works ✓ +- `use crate::ppo::` — same via re-export from `ml_ppo` ✓ - `use crate::tft::` — same via re-export from `ml_supervised` ✓ - `use crate::ensemble::` — same via re-export from `ml_infra` ✓ - `use crate::MLError` — from `ml_core` via `pub use ml_core::*` ✓ @@ -804,7 +883,8 @@ Expected: Same test count as baseline (2506+), 0 failures Run each in parallel: ```bash SQLX_OFFLINE=true cargo test -p ml-core --lib 2>&1 | tail -5 -SQLX_OFFLINE=true cargo test -p ml-rl --lib 2>&1 | tail -5 +SQLX_OFFLINE=true cargo test -p ml-dqn --lib 2>&1 | tail -5 +SQLX_OFFLINE=true cargo test -p ml-ppo --lib 2>&1 | tail -5 SQLX_OFFLINE=true cargo test -p ml-supervised --lib 2>&1 | tail -5 SQLX_OFFLINE=true cargo test -p ml-infra --lib 2>&1 | tail -5 ``` @@ -859,23 +939,25 @@ Run: `SQLX_OFFLINE=true cargo test -p common --lib 2>&1 | tail -5` **Step 1: Update MEMORY.md** -Update the Architecture section to reflect the new 5-crate ML structure. Update the ML Model Training section with new crate paths. Remove any stale references to `crates/ml/src/dqn/mixed_precision.rs` etc. +Update the Architecture section to reflect the new 6-crate ML structure. Update the ML Model Training section with new crate paths. Remove any stale references to `crates/ml/src/dqn/mixed_precision.rs` etc. **Step 2: Final commit** ```bash git add -A -git commit -m "refactor(ml): complete crate split — 5 crates, parallel compilation +git commit -m "refactor(ml): complete crate split — 6 crates, 3-way parallel compilation Split the monolithic ml crate (260K lines, 55s compile) into: - ml-core: shared types, traits, features, data, checkpoint, safety -- ml-rl: DQN + PPO + cuda_pipeline +- ml-dqn: DQN + cuda_pipeline +- ml-ppo: PPO (independent of ml-dqn) - ml-supervised: TFT, Mamba, Liquid, TGNN, TLOB, KAN, xLSTM, Diffusion - ml-infra: hyperopt, ensemble, trainers, benchmark, deployment - ml: thin facade re-exporting everything +3-way parallel compilation (ml-dqn + ml-ppo + ml-supervised). Zero API changes for downstream consumers. -Incremental rebuild after model edit: ~55s → ~10-15s." +Incremental rebuild after model edit: ~55s → ~6-12s." ``` --- @@ -886,20 +968,23 @@ Incremental rebuild after model edit: ~55s → ~10-15s." |------|-------------|-----------|------------| | 1 | Verify clean baseline | verify | — | | 2 | Create sub-crate dirs + workspace | scaffold | 1 | -| 3 | Extract shared items from dqn/ | refactor | 2 | +| 3 | Extract shared items from dqn/ + TradingAction | refactor | 2 | | 4 | Write ml-core Cargo.toml | config | 2 | | 5 | Move core modules to ml-core | **large** | 3, 4 | -| 6 | Write ml-rl Cargo.toml | config | 4 | -| 7 | Move RL modules to ml-rl | **large** | 5, 6 | +| 6 | Write ml-dqn Cargo.toml | config | 4 | +| 7a | Move DQN + cuda_pipeline to ml-dqn | **large** | 5, 6 | +| 7b | Write ml-ppo Cargo.toml + move PPO | **large** | 5 | | 8 | Write ml-supervised Cargo.toml | config | 4 | | 9 | Move supervised models | **large** | 5, 8 | -| 10 | Write ml-infra Cargo.toml | config | 6, 8 | -| 11 | Move infra modules | **large** | 7, 9, 10 | +| 10 | Write ml-infra Cargo.toml | config | 6, 7b, 8 | +| 11 | Move infra modules | **large** | 7a, 7b, 9, 10 | | 12 | Clean up ml facade | medium | 11 | | 13 | Full verification | verify | 12 | | 14 | Update common dev-dep | small | 12 | | 15 | Update memory + final commit | small | 13 | +Note: Tasks 7a, 7b, and 9 can execute in parallel (they move independent module sets). + ## Critical Invariants (Verify After Every Task) 1. **No stubs**: Every function must be wired to its real implementation