Two-part fix that finally removes ~35% of ml-* sub-crates from
service-binary build closures:
1. crates/ml/Cargo.toml: 8 leaf-level ml-* sub-crates become optional
behind feature flags (one feature per `pub mod` in lib.rs):
ml-backtesting ↔ feature `backtest-mod` (ml::backtesting)
ml-paper-trading ↔ feature `paper-trading-mod` (ml::paper_trading)
ml-stress-testing ↔ feature `stress-testing-mod` (ml::stress_testing)
ml-explainability ↔ feature `explainability-mod` (ml::explainability)
ml-universe ↔ feature `universe-mod` (ml::universe)
ml-regime-detection ↔ feature `regime-detection-mod`(ml::regime_detection)
ml-validation ↔ feature `validation-mod` (ml::validation)
ml-data-validation ↔ feature `data-validation-mod` (ml::data_validation)
Aggregated into the umbrella `full-stack` feature, which is in
`default = [...]` so existing `ml.workspace = true` callers see
identical behavior (testing/integration, crates/backtesting).
2. services/trading_service + services/backtesting_service: switched
from `ml.workspace = true` to explicit `path = "../../crates/ml"`
form with `default-features = false`. This is necessary because
cargo 1.89 silently ignores `default-features = false` when
combined with `workspace = true` (a known cargo limitation).
Path form bypasses the workspace dep and applies the opt-out.
Verified by `cargo tree -p X | grep ml-* | wc -l`:
trading-service 23 → 16 (-30%)
backtesting-service 23 → 16 (-30%)
Source-grep verified neither service references any of the 8 gated
modules (`use ml::backtesting`, `use ml::explainability`, etc. all
zero hits in src/). The only `ml::explainability` mention in
trading-service is a string in an error log — not a code path.
ml-training-service and trading-agent-service were already on path
form with default-features = false; they're unaffected here.
cargo check --workspace passes.