Restore 45-action factored space via Branching DQN (Tavakoli 2018), outputting 11 Q-values (5+3+3) instead of 45. This was reduced to 5 exposure-only actions during debugging and was never intended as permanent. - Enable use_branching: true by default in DQNConfig and DQNHyperparameters - Add branching paths to select_action_with_confidence and select_action_inference - Update agent.rs select_action_factored for branching-aware selection - Expand CountBonus to per-branch tracking with bonuses_branched() - Add order_type + urgency distribution tracking in monitoring - Add DQN_ORDER_ACTIONS=3, DQN_URGENCY_ACTIONS=3, DQN_TOTAL_ACTIONS=45 to CUDA header - Fix 7 pre-existing clippy doc_markdown errors in regime_conditional.rs - Fix pre-existing cognitive_complexity in replay_buffer_type.rs (extract helpers) - Fix flaky GPU test OOM under parallel execution (CPU fallback + test VRAM safety) - Delete unused flash_attention submodules (block_sparse, causal_masking, etc.) - Add GPU hot-path guard scripts and ensemble/hyperopt adapter improvements Tests: ml-dqn 416/0, ml 905/0, clippy 0 errors on both crates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
27 KiB
Forward-Port Main onto ML Crate Split Branch — Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Port 24 commits of GPU performance work from main onto feature/ml-crate-split-phase2, adapting file paths to the new sub-crate layout.
Architecture: Cherry-pick + path-rewrite in 8 phases. Commits that only touch sub-crates (ml-core, ml-dqn, etc.) or infra files apply directly. Commits that touch crates/ml/ files which were moved to sub-crates need path-rewritten patches. Deleted files (parquet, smoke_tests) are triaged. Compiler-driven fixup after each phase.
Tech Stack: Rust workspace, git format-patch/apply, sed path rewriting, SQLX_OFFLINE=true cargo check --workspace
Worktree: .worktrees/ml-split-p2 on branch feature/ml-crate-split-phase2
Build command: SQLX_OFFLINE=true cargo check --workspace
Test command: SQLX_OFFLINE=true cargo test -p <crate> --lib
Clippy: SQLX_OFFLINE=true cargo clippy --workspace -- -D warnings
File Move Mapping (Branch Reality)
These files were moved from crates/ml/src/ to sub-crates on the branch. Main modified them at their OLD paths. Patches must target the NEW paths.
OLD PATH (on main) → NEW PATH (on branch)
─────────────────────────────────────────────────────────────────────────
crates/ml/src/cuda_pipeline/* → crates/ml-core/src/cuda_pipeline/*
crates/ml/src/features/extraction.rs → crates/ml-features/src/extraction.rs
crates/ml/src/features/production_adapter.rs → crates/ml-features/src/production_adapter.rs
crates/ml/src/features/unified.rs → crates/ml-features/src/unified.rs
crates/ml/src/features/mod.rs → crates/ml-features/src/lib.rs (merged into)
crates/ml/src/trainers/dqn/trainer.rs → crates/ml-dqn/src/trainer/trainer.rs
crates/ml/src/trainers/dqn/config.rs → crates/ml-dqn/src/trainer/config.rs
crates/ml/src/trainers/dqn/data_loading.rs → crates/ml-dqn/src/trainer/data_loading.rs
crates/ml/src/trainers/dqn/features.rs → crates/ml-dqn/src/trainer/features.rs
crates/ml/src/trainers/dqn/mod.rs → crates/ml-dqn/src/trainer/mod.rs
crates/ml/src/trainers/dqn/monitoring.rs → crates/ml-dqn/src/trainer/monitoring.rs
crates/ml/src/trainers/ppo.rs → crates/ml-ppo/src/trainer.rs
crates/ml/src/hyperopt/adapters/dqn.rs → crates/ml-hyperopt/src/adapters/dqn.rs
crates/ml/src/hyperopt/adapters/ppo.rs → crates/ml-hyperopt/src/adapters/ppo.rs
crates/ml/src/hyperopt/adapters/continuous_ppo.rs → crates/ml-hyperopt/src/adapters/continuous_ppo.rs
crates/ml/src/hyperopt/adapters/mamba2.rs → crates/ml-hyperopt/src/adapters/mamba2.rs
crates/ml/src/hyperopt/shared_data.rs → crates/ml-hyperopt/src/shared_data.rs
crates/ml/src/ensemble/model_adapter.rs → crates/ml-ensemble/src/model_adapter.rs
STILL IN crates/ml/ (no rewrite needed):
src/data_loaders/*, src/walk_forward.rs, src/hyperopt/adapters/tft.rs,
examples/*, tests/*, Cargo.toml
DELETED on branch (main's changes are OBSOLETE):
src/data_loaders/parquet_utils.rs — branch intentionally removed all parquet code
src/feature_cache.rs — branch deleted (superseded by ml-features)
src/trainers/tft_parquet.rs — branch deleted (parquet removal)
src/trainers/dqn/smoke_tests/* — branch deleted entire directory (5 files, ~900 LOC)
Phase 0: Preparation
Task 0a: Create backup tag
Step 1: Tag current branch state
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git tag backup/ml-split-p2-before-forward-port
Step 2: Verify clean working tree
git status
Expected: nothing to commit, working tree clean
Step 3: Record baseline test counts
SQLX_OFFLINE=true cargo test --workspace --lib 2>&1 | grep "test result" | sort
Save output for comparison after all phases.
Phase 1: Infrastructure-Only Commits (3 commits, clean cherry-pick)
These commits touch only infra/ files — no crates/ conflicts at all.
Task 1a: Cherry-pick infra commits
Commits:
47d49595fix(train): correct --output to --output-dir arg, add Prometheus annotations9d6a04abfix(grafana): add 20 missing metric panels to training dashboard356f1d29fix(train): remove duplicate annotations block from rebase artifact
Step 1: Cherry-pick all three (oldest first)
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git cherry-pick 47d49595 9d6a04ab 356f1d29
Expected: clean apply, no conflicts.
Step 2: Verify
SQLX_OFFLINE=true cargo check --workspace
Step 3: If any conflict: resolve, git add, git cherry-pick --continue
Phase 2: Sub-Crate-Only Commits (5 commits, clean cherry-pick)
These commits ONLY modify files inside crates/ml-core/, crates/ml-dqn/, crates/ml-ppo/, or crates/common/ — files that exist at the same paths on both branches.
Task 2a: Cherry-pick sub-crate performance commits
Commits (chronological):
0355fb17perf(metrics): expose step-level DQN metrics to Prometheus gaugesdb65eb56perf(gpu): eliminate GPU→CPU sync barriers from training hot pathee12f1d9perf(gpu): zero-sync gradient clipping — eliminate all GPU→CPU barriers379c0beefix(dqn): cast F32 constants to input dtype for BF16 mixed precision on H1001b9f09fcperf(dqn): eliminate GPU→CPU roundtrip in branching action decomposition
Step 1: Cherry-pick all five
git cherry-pick 0355fb17 db65eb56 ee12f1d9 379c0bee 1b9f09fc
Step 2: If 1b9f09fc fails (branching.rs may not exist yet — it's added by 89c3fb89 which comes in Phase 5): skip it for now, cherry-pick it after Phase 5.
git cherry-pick --abort # if it failed
# We'll retry 1b9f09fc after Phase 5
Step 3: Verify
SQLX_OFFLINE=true cargo check --workspace
Step 4: Commit checkpoint message if needed
Phase 3: Mixed Commits — Sub-Crate + Simple ML Path Rewrites (7 commits)
These commits touch sub-crate files (apply cleanly) PLUS crates/ml/ files that were moved. Strategy: cherry-pick, let sub-crate parts apply, then manually fix the crates/ml/ parts using path-rewritten patches.
Task 3a: GPU PER hot path (e35ead5f)
Main's changes: ml-dqn/dqn.rs, ml-dqn/quantile_regression.rs (clean), + ml/src/cuda_pipeline/gpu_experience_collector.rs (→ ml-core), ml/src/trainers/dqn/config.rs (→ ml-dqn/trainer), ml/src/trainers/dqn/trainer.rs (→ ml-dqn/trainer)
Step 1: Generate and rewrite patch
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 e35ead5f --stdout > /tmp/e35ead5f.patch
# Rewrite moved file paths
sed -i 's|a/crates/ml/src/cuda_pipeline/|a/crates/ml-core/src/cuda_pipeline/|g' /tmp/e35ead5f.patch
sed -i 's|b/crates/ml/src/cuda_pipeline/|b/crates/ml-core/src/cuda_pipeline/|g' /tmp/e35ead5f.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/e35ead5f.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/e35ead5f.patch
Step 2: Apply with reject mode
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/e35ead5f.patch
Step 3: Resolve any .rej files. Check for use crate:: paths that need updating:
- In ml-core files:
use crate::is already correct (they're in ml-core) - In ml-dqn/trainer files:
use crate::cuda_pipeline::→use ml_core::cuda_pipeline::
Step 4: Compiler-driven fixup
SQLX_OFFLINE=true cargo check -p ml-core -p ml-dqn
Fix any remaining import errors.
Step 5: Commit
git add -A
git commit -m "forward-port(e35ead5f): wire GPU PER into hot path (path-adapted)"
Task 3b: IQN GPU PER weights + CUDA default (b616d024)
Main's changes: 10 sub-crate Cargo.tomls (cuda default feature) + ml/Cargo.toml + ml/src/trainers/dqn/config.rs (→ ml-dqn/trainer)
Step 1: Generate and rewrite patch
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 b616d024 --stdout > /tmp/b616d024.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/b616d024.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/b616d024.patch
Step 2: Apply
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/b616d024.patch
Step 3: Cargo.toml conflicts are likely — the sub-crate Cargo.tomls have different dependency lists on the branch. For each .rej file in a Cargo.toml:
- Main added
default-features = ["cuda"]— manually add this to the branch's version - Main may have version bumps — adopt them
Step 4: Also add default-features = ["cuda"] to any NEW sub-crate Cargo.tomls the branch created (ml-data, ml-benchmark, ml-deployment) that main didn't know about.
Step 5: Verify + commit
SQLX_OFFLINE=true cargo check --workspace
git add -A
git commit -m "forward-port(b616d024): IQN GPU PER weights, CUDA default features (path-adapted)"
Task 3c: Eliminate CPU tensor ops (801781a4)
Main's changes: ml-core/gradient_accumulation.rs, ml-dqn/dqn.rs, ml-dqn/gpu_replay_buffer.rs (clean) + ml/src/trainers/dqn/config.rs (→ ml-dqn/trainer)
Step 1-5: Same pattern as 3a — format-patch, sed trainer path, apply, fix, commit.
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 801781a4 --stdout > /tmp/801781a4.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/801781a4.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/801781a4.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/801781a4.patch
# Fix .rej files, cargo check, commit
Task 3d: Replace remaining CPU tensor allocations (5191fa02)
Main's changes: ml-dqn/distributional.rs, ml-dqn/dqn.rs, ml-dqn/quantile_regression.rs, ml-ppo/ppo.rs — ALL sub-crate files, no path rewrite needed.
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 5191fa02 --stdout > /tmp/5191fa02.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/5191fa02.patch
# Should apply cleanly. Verify + commit.
Task 3e: GPU searchsorted kernel (0f45537e)
Main's changes: ml-core/mixed_precision.rs, ml-dqn/gpu_replay_buffer.rs, ml-dqn/searchsorted_kernel.cu — all sub-crate.
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 0f45537e --stdout > /tmp/0f45537e.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/0f45537e.patch
Note: searchsorted_kernel.cu is a new file — verify it's created in crates/ml-dqn/src/.
Task 3f: BF16 mixed precision default (7f3066e6)
Main's changes: ml-core/mixed_precision.rs, ml-dqn/curiosity.rs, ml-dqn/network.rs, ml-hyperopt/traits.rs (all clean) + ml/src/hyperopt/adapters/dqn.rs (→ ml-hyperopt/adapters)
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 7f3066e6 --stdout > /tmp/7f3066e6.patch
sed -i 's|a/crates/ml/src/hyperopt/adapters/|a/crates/ml-hyperopt/src/adapters/|g' /tmp/7f3066e6.patch
sed -i 's|b/crates/ml/src/hyperopt/adapters/|b/crates/ml-hyperopt/src/adapters/|g' /tmp/7f3066e6.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/7f3066e6.patch
Task 3g: BF16 softmax overflow (fb18e0f1)
Main's changes: ml-dqn/distributional_dueling.rs, ml-dqn/rainbow_network.rs (clean) + ml/src/trainers/dqn/config.rs (→ ml-dqn/trainer)
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 fb18e0f1 --stdout > /tmp/fb18e0f1.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/fb18e0f1.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/fb18e0f1.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/fb18e0f1.patch
Task 3-checkpoint: Verify Phase 3
SQLX_OFFLINE=true cargo check --workspace
SQLX_OFFLINE=true cargo clippy --workspace -- -D warnings 2>&1 | head -30
Commit any remaining fixups.
Phase 4: The Monster Commit — GPU-Native Regime Classification (c0c44a5f)
This single commit touches 42 files (+821/-514 lines) spanning cuda_pipeline, features, data_loaders, ensemble, hyperopt, trainers, and tests. It must be decomposed into per-destination patches.
Task 4a: Extract and split the patch
Step 1: Generate the full patch
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 c0c44a5f --stdout > /tmp/c0c44a5f-full.patch
Step 2: Create per-destination copies with path rewrites
# Copy A: cuda_pipeline changes → ml-core
cp /tmp/c0c44a5f-full.patch /tmp/c0c44a5f-cuda.patch
sed -i 's|a/crates/ml/src/cuda_pipeline/|a/crates/ml-core/src/cuda_pipeline/|g' /tmp/c0c44a5f-cuda.patch
sed -i 's|b/crates/ml/src/cuda_pipeline/|b/crates/ml-core/src/cuda_pipeline/|g' /tmp/c0c44a5f-cuda.patch
# Copy B: features changes → ml-features
cp /tmp/c0c44a5f-full.patch /tmp/c0c44a5f-features.patch
sed -i 's|a/crates/ml/src/features/|a/crates/ml-features/src/|g' /tmp/c0c44a5f-features.patch
sed -i 's|b/crates/ml/src/features/|b/crates/ml-features/src/|g' /tmp/c0c44a5f-features.patch
# Copy C: trainers/dqn changes → ml-dqn/trainer
cp /tmp/c0c44a5f-full.patch /tmp/c0c44a5f-trainer.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/c0c44a5f-trainer.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/c0c44a5f-trainer.patch
# Copy D: hyperopt/adapters changes → ml-hyperopt/adapters
cp /tmp/c0c44a5f-full.patch /tmp/c0c44a5f-hyperopt.patch
sed -i 's|a/crates/ml/src/hyperopt/adapters/|a/crates/ml-hyperopt/src/adapters/|g' /tmp/c0c44a5f-hyperopt.patch
sed -i 's|b/crates/ml/src/hyperopt/adapters/|b/crates/ml-hyperopt/src/adapters/|g' /tmp/c0c44a5f-hyperopt.patch
# Copy E: ensemble changes → ml-ensemble
cp /tmp/c0c44a5f-full.patch /tmp/c0c44a5f-ensemble.patch
sed -i 's|a/crates/ml/src/ensemble/|a/crates/ml-ensemble/src/|g' /tmp/c0c44a5f-ensemble.patch
sed -i 's|b/crates/ml/src/ensemble/|b/crates/ml-ensemble/src/|g' /tmp/c0c44a5f-ensemble.patch
# Copy F: trainers/ppo changes → ml-ppo/trainer
cp /tmp/c0c44a5f-full.patch /tmp/c0c44a5f-ppo.patch
sed -i 's|a/crates/ml/src/trainers/ppo.rs|a/crates/ml-ppo/src/trainer.rs|g' /tmp/c0c44a5f-ppo.patch
sed -i 's|b/crates/ml/src/trainers/ppo.rs|b/crates/ml-ppo/src/trainer.rs|g' /tmp/c0c44a5f-ppo.patch
Task 4b: Apply each sub-patch
Step 1: Apply in dependency order. Use --reject throughout.
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
# A: ml-core cuda_pipeline
git apply --reject /tmp/c0c44a5f-cuda.patch 2>&1 | grep -E "Applied|Rejected"
# B: ml-features
git apply --reject /tmp/c0c44a5f-features.patch 2>&1 | grep -E "Applied|Rejected"
# C: ml-dqn trainer
git apply --reject /tmp/c0c44a5f-trainer.patch 2>&1 | grep -E "Applied|Rejected"
# D: ml-hyperopt adapters
git apply --reject /tmp/c0c44a5f-hyperopt.patch 2>&1 | grep -E "Applied|Rejected"
# E: ml-ensemble
git apply --reject /tmp/c0c44a5f-ensemble.patch 2>&1 | grep -E "Applied|Rejected"
# F: ml-ppo
git apply --reject /tmp/c0c44a5f-ppo.patch 2>&1 | grep -E "Applied|Rejected"
# G: The original patch for files that DIDN'T move (data_loaders, tests, examples, etc.)
git apply --reject /tmp/c0c44a5f-full.patch 2>&1 | grep -E "Applied|Rejected"
Step 2: Each patch will partially apply and partially reject (since each copy has ALL hunks but only some paths match). Resolve .rej files one by one.
Step 3: Handle special cases:
features/mod.rson main → merged intoml-features/src/lib.rson branch. Manually read the diff hunk and apply to lib.rs.trainers/dqn/smoke_tests/*— main CREATED these files; branch DELETED the directory. Decision: Skip. These smoke tests tested the monolithic trainer; they need to be rewritten for ml-dqn's trainer structure. Create a TODO in the commit message.trainers/tft_parquet.rs— DELETED on branch. Skip (parquet removal intentional).data_loaders/parquet_utils.rs— DELETED on branch. Skip.feature_cache.rs— DELETED on branch. Skip.hyperopt/shared_data.rs→ml-hyperopt/src/shared_data.rs— apply shared_data changes with path rewrite.
Step 4: Clean up reject files
find . -name "*.rej" -type f
# Review each, apply manually or confirm skip, then delete
find . -name "*.rej" -type f -delete
Task 4c: Compiler-driven fixup for regime classification
This is the most intensive fixup step. The regime classification commit changed function signatures and data flow across crate boundaries.
Step 1: Run compiler
SQLX_OFFLINE=true cargo check --workspace 2>&1 | head -100
Step 2: Fix import paths. Common patterns:
# In ml-core/cuda_pipeline files:
use crate::mixed_precision::training_dtype → already correct (in ml-core)
# In ml-dqn/trainer files:
use crate::cuda_pipeline:: → use ml_core::cuda_pipeline::
use crate::features:: → use ml_features::
# In ml-hyperopt/adapters files:
use crate::trainers::dqn:: → use ml_dqn::trainer::
use crate::features:: → use ml_features::
# In ml-ensemble files:
use crate::features:: → use ml_features::
Step 3: Add missing crate dependencies to Cargo.toml files if needed (e.g., if ml-hyperopt now needs ml-features).
Step 4: Iterate: cargo check, fix, cargo check, fix... until clean.
Step 5: Commit
git add -A
git commit -m "forward-port(c0c44a5f): GPU-native regime classification with 42-dim features (decomposed + path-adapted)
Skipped: smoke_tests/ (deleted on branch), parquet_utils.rs, feature_cache.rs, tft_parquet.rs
TODO: Recreate DQN trainer smoke tests in crates/ml-dqn/tests/"
Phase 5: Heavy Commits (4 commits)
Task 5a: GPU PER monitoring (d12273e1, 17 files, +1148/-115)
Main's changes span: cuda_pipeline (→ ml-core), trainers/dqn (→ ml-dqn/trainer), hyperopt/adapters/dqn (→ ml-hyperopt), smoke_tests (→ DELETED), + ml-dqn sub-crate files, ml-core files.
Step 1: Full rewrite-and-apply
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 d12273e1 --stdout > /tmp/d12273e1.patch
# Apply all path rewrites
sed -i 's|a/crates/ml/src/cuda_pipeline/|a/crates/ml-core/src/cuda_pipeline/|g' /tmp/d12273e1.patch
sed -i 's|b/crates/ml/src/cuda_pipeline/|b/crates/ml-core/src/cuda_pipeline/|g' /tmp/d12273e1.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/d12273e1.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/d12273e1.patch
sed -i 's|a/crates/ml/src/hyperopt/adapters/|a/crates/ml-hyperopt/src/adapters/|g' /tmp/d12273e1.patch
sed -i 's|b/crates/ml/src/hyperopt/adapters/|b/crates/ml-hyperopt/src/adapters/|g' /tmp/d12273e1.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/d12273e1.patch
Step 2: The smoke_tests/ hunks will fail (directory doesn't exist on branch). This is expected — these 5 files (~900 LOC) were deleted on the branch. The .rej files for smoke_tests can be safely deleted.
Step 3: Fix imports, cargo check, commit.
find . -name "*.rej" -delete
SQLX_OFFLINE=true cargo check --workspace
git add -A
git commit -m "forward-port(d12273e1): GPU PER monitoring fix (path-adapted, smoke_tests skipped)"
Task 5b: Branching DQN with GPU Rainbow parity (89c3fb89, 10 files, +3207/-125)
Main's changes: ml-core/fill_simulator.rs, ml-core/lib.rs, ml-dqn/branching.rs (NEW), ml-dqn/dqn.rs, ml-dqn/lib.rs (all sub-crate — clean) + ml/src/hyperopt/adapters/dqn.rs (→ ml-hyperopt), ml/src/trainers/dqn/config.rs (→ ml-dqn/trainer), ml/src/trainers/dqn/trainer.rs (→ ml-dqn/trainer), infra/scripts/train.sh, docs/
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 89c3fb89 --stdout > /tmp/89c3fb89.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/89c3fb89.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/89c3fb89.patch
sed -i 's|a/crates/ml/src/hyperopt/adapters/|a/crates/ml-hyperopt/src/adapters/|g' /tmp/89c3fb89.patch
sed -i 's|b/crates/ml/src/hyperopt/adapters/|b/crates/ml-hyperopt/src/adapters/|g' /tmp/89c3fb89.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/89c3fb89.patch
Note: branching.rs is a NEW file that goes into ml-dqn/src/ — should apply cleanly. Verify ml-dqn/src/lib.rs includes pub mod branching;.
Fix imports, cargo check, commit.
Task 5c: Eliminate OOM in hyperopt (fe223b38, 9 files, +477/-129)
Main's changes: ml-dqn/dqn.rs, ml-dqn/noisy_layers.rs, ml-hyperopt/traits.rs (clean) + ml/src/cuda_pipeline/gpu_experience_collector.rs (→ ml-core), ml/src/hyperopt/adapters/dqn.rs (→ ml-hyperopt), ml/src/trainers/dqn/config.rs (→ ml-dqn/trainer), ml/src/trainers/dqn/trainer.rs (→ ml-dqn/trainer), ml/tests/* (stay in ml)
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 fe223b38 --stdout > /tmp/fe223b38.patch
sed -i 's|a/crates/ml/src/cuda_pipeline/|a/crates/ml-core/src/cuda_pipeline/|g' /tmp/fe223b38.patch
sed -i 's|b/crates/ml/src/cuda_pipeline/|b/crates/ml-core/src/cuda_pipeline/|g' /tmp/fe223b38.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/fe223b38.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/fe223b38.patch
sed -i 's|a/crates/ml/src/hyperopt/adapters/|a/crates/ml-hyperopt/src/adapters/|g' /tmp/fe223b38.patch
sed -i 's|b/crates/ml/src/hyperopt/adapters/|b/crates/ml-hyperopt/src/adapters/|g' /tmp/fe223b38.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/fe223b38.patch
Fix, check, commit.
Task 5d: Retry branching action decomposition (1b9f09fc)
If this was skipped in Phase 2 because branching.rs didn't exist yet:
git cherry-pick 1b9f09fc
Should apply cleanly now that 89c3fb89 added branching.rs.
Phase 6: CI/Metrics Mixed Commits (2 commits)
Task 6a: Unblock CPU service builds (7751f761)
Main's changes: Cargo.toml (root), ml-dqn/regime_conditional.rs (clean), ml/src/trainers/dqn/trainer.rs (→ ml-dqn/trainer), infra/*
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 7751f761 --stdout > /tmp/7751f761.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/7751f761.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/7751f761.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/7751f761.patch
Task 6b: Wire training pod scraping (e89fbc2b)
Main's changes: ml/src/trainers/dqn/trainer.rs (→ ml-dqn/trainer), ml/src/trainers/ppo.rs (→ ml-ppo/trainer.rs), infra/*
cd /home/jgrusewski/Work/foxhunt
git format-patch -1 e89fbc2b --stdout > /tmp/e89fbc2b.patch
sed -i 's|a/crates/ml/src/trainers/dqn/|a/crates/ml-dqn/src/trainer/|g' /tmp/e89fbc2b.patch
sed -i 's|b/crates/ml/src/trainers/dqn/|b/crates/ml-dqn/src/trainer/|g' /tmp/e89fbc2b.patch
sed -i 's|a/crates/ml/src/trainers/ppo.rs|a/crates/ml-ppo/src/trainer.rs|g' /tmp/e89fbc2b.patch
sed -i 's|b/crates/ml/src/trainers/ppo.rs|b/crates/ml-ppo/src/trainer.rs|g' /tmp/e89fbc2b.patch
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git apply --reject /tmp/e89fbc2b.patch
Fix, check, commit.
Phase 7: Visibility & Import Fixup Pass
After all patches are applied, some items may have pub(crate) visibility that's now insufficient across crate boundaries.
Task 7a: Full compiler sweep
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
SQLX_OFFLINE=true cargo check --workspace 2>&1 | tee /tmp/forward-port-errors.log
grep "error\[" /tmp/forward-port-errors.log | sort -u | head -50
Task 7b: Fix visibility errors
Common patterns:
pub(crate) fn foo()in ml-core that ml-dqn now calls → change topub fn foo()pub(crate) struct Barin ml-core used by ml-hyperopt → change topub struct Bar
Task 7c: Fix missing dependency declarations
If ml-hyperopt now imports ml-features but it's not in Cargo.toml:
[dependencies]
ml-features = { workspace = true }
Task 7d: Clippy clean
SQLX_OFFLINE=true cargo clippy --workspace -- -D warnings 2>&1 | head -50
Fix any new clippy warnings introduced by forward-ported code.
Task 7e: Commit fixup
git add -A
git commit -m "fix: resolve visibility and import issues from forward-port"
Phase 8: Final Verification
Task 8a: Full workspace build
SQLX_OFFLINE=true cargo check --workspace
Expected: success, 0 errors.
Task 8b: Full clippy
SQLX_OFFLINE=true cargo clippy --workspace -- -D warnings
Expected: 0 errors, 0 warnings (excluding known ml-dqn dead field warnings from branch).
Task 8c: Test count comparison
# Run all ml-* tests
for crate in crates/ml-*/; do
name=$(basename "$crate")
echo -n "$name: "
SQLX_OFFLINE=true cargo test -p "$name" --lib 2>&1 | grep "test result" | tail -1
done
# Run ml orchestration tests
echo -n "ml: "
SQLX_OFFLINE=true cargo test -p ml --lib 2>&1 | grep "test result" | tail -1
Compare totals with Phase 0 baseline. Total should be ≥ baseline (main added tests).
Task 8d: Squash or keep history
Option A (recommended): Keep granular forward-port commits for traceability:
forward-port(e35ead5f): wire GPU PER into hot path (path-adapted)
forward-port(b616d024): IQN GPU PER weights, CUDA default features (path-adapted)
...
Option B: Squash all forward-port commits into one:
git rebase -i backup/ml-split-p2-before-forward-port
# Mark all forward-port commits as "squash"
Task 8e: Update plan document
Add a completion note to docs/plans/2026-03-08-ml-crate-split-phase2.md noting that main's GPU changes have been forward-ported.
Skip List (Merge Commits)
These are merge commits on main — skip them entirely, their content is included in the non-merge commits:
06d0a8d6Merge branch 'feature/dqn-branching'3a37454eMerge branch 'feature/dqn-branching'3c3812d9Merge branch 'worktree-gpu-hotpath-audit'
Deleted File Triage Summary
| File | Decision | Reason |
|---|---|---|
parquet_utils.rs |
Skip | Branch intentionally deleted all parquet code (-3K LOC) |
feature_cache.rs |
Skip | Superseded by ml-features architecture |
tft_parquet.rs |
Skip | Parquet removal |
smoke_tests/feature_coverage.rs |
TODO | 156 LOC — recreate in ml-dqn/tests/ |
smoke_tests/gpu_residency.rs |
TODO | 272 LOC — recreate in ml-dqn/tests/ |
smoke_tests/helpers.rs |
TODO | 85 LOC — recreate in ml-dqn/tests/ |
smoke_tests/training_stability.rs |
TODO | 254 LOC — recreate in ml-dqn/tests/ |
smoke_tests/performance.rs |
TODO | 146 LOC — recreate in ml-dqn/tests/ |
Smoke tests total ~900 LOC. They tested the monolithic DQN trainer. After the forward-port, create a follow-up task to rewrite them as integration tests in crates/ml-dqn/tests/.
Rollback
If anything goes catastrophically wrong:
cd /home/jgrusewski/Work/foxhunt/.worktrees/ml-split-p2
git reset --hard backup/ml-split-p2-before-forward-port