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 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user