Cluster's 9-quarter precompute_features hung silently after the
"alpha pipeline inputs" log line and was killed at ~75 minutes — local
1Q profiling showed the alpha pipeline is strictly single-threaded
(extract_alpha_features is one for-loop over n_output bars with no
rayon usage), so 9Q would have needed ~72 min on one CPU even with no
external interference. That's a kill window large enough to be brittle
under any transient kubelet/argo signal.
Fix: split the emit range across `rayon::current_num_threads()` chunks.
Each chunk gets fresh aggregator state and pre-rolls 2000 leading bars
without emission so Hawkes excitation / Bouchaud EMA / frac-diff FIR /
LOB PCA covariance / microprice EMA / spread_decomp running stats are
saturated before the first emitted row. Trade-feed semantics preserved
via `trades.partition_point` seeding per chunk — each trade still
visits exactly one aggregator chain.
Local 1Q ES benchmark (9-core box):
- before: 2:19 wall, 101% CPU (1 core)
- after: 0:27 wall, 915% CPU (9 cores)
- 5.1× speedup; same row count + Alpha dim 134 + 468MB output
Extrapolated 9Q on cluster's 32-vCPU HM pool: ~4-5 min for the alpha
portion (vs ~72 min before). Well under any plausible kill window.
Numerical caveat: not bit-identical to a fully-sequential run for
chunks k > 0. Aggregators initialise at default state instead of
carrying real history across the chunk seam; the 2000-bar warmup
refills Hawkes's 500-event history twice over and saturates the
longer-memory EMAs, so post-warmup drift is bounded by floating-point
ε. The two existing in-crate unit tests (`test_extract_alpha_features_*`)
still pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>