# Rust forecast spike Answers one question: can the flood forecast be served from Rust without train/serve skew, while training stays in Python (scikit-learn)? Assessment and migration plan: [docs/RUST_REWRITE.md](../../docs/RUST_REWRITE.md). - `export/export_fixture.py`: dumps `models/flood_P.1.joblib` (all 9 HGB heads) as flat tree arrays, plus two fixtures from `models/cache` (Aug-Oct 2024 record flood, Jun-Aug 2026): the observed hourly grid of P.1 and its 7 upstream gauges, rain, the pandas feature matrix and every head's sklearn prediction. - `src/features.rs`: port of `src/ml/features.py::build_features` (P.1 path: lags, rises, rolling stats, upstream leads, season, rain). - `src/hgb.rs`: HistGradientBoosting inference (~90 lines). - `src/main.rs`: compares bit-for-bit and times serving-shaped work. ```bash cd spikes/rust-forecast/export uv run --project ../../.. python export_fixture.py # writes ../data/*.json (gitignored) cd .. && cargo run --release uv run --project ../.. python export/time_python.py # Python timing for comparison ``` Result (model hgb-v3+cbb3bf7, 3,600 hourly rows): | | Result | | --- | --- | | Features, 68 columns x 3,600 rows | 244,800 / 244,800 cells bit-identical | | Regression heads (max_6/12/24) | bit-identical on every row | | Classifier heads (warn/danger) | equal to the last ulp (<= 2.2e-16, `exp` vs scipy `expit`) | | One station: 336 h window -> features + 9 heads | Rust 0.25 ms, Python 158 ms | | Model load | Rust 16 ms (JSON), Python 199 ms (joblib) | Two traps the spike had to get past, both of which flip tree branches because HGB thresholds often equal real data values exactly: 1. `serde_json` parses floats best-effort (can be 1 ulp off) unless the `float_roundtrip` feature is on. 2. pandas `rolling().sum()/.mean()` are incremental with Kahan compensation, a "run of identical values" shortcut and a sign clamp. A plain window sum differs in the last bits; `rolling_kahan()` replicates pandas exactly. Not covered yet: dam features (Mae Ngat), HII gap fill, Open-Meteo catchment mean, the heuristic fallback, stage probabilities, the other 14 stations.