From 61c4b043c688fa9e8b3ecd9d2f68355ef06613bc Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Fri, 17 Apr 2026 01:27:33 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20fxcache=20version=20auto-invalidation?= =?UTF-8?q?=20=E2=80=94=20FXCACHE=5FVERSION=3D2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version constant in fxcache.rs. validate() rejects stale versions with clear error message. ensure-fxcache Argo template now deletes old cache and regenerates unconditionally. No manual PVC cleanup needed — version mismatch triggers automatic regeneration. v2: OFI_DIM=20 (20 microstructure features). Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/ml/src/fxcache.rs | 13 +++++++++---- infra/k8s/argo/train-template.yaml | 12 ++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/ml/src/fxcache.rs b/crates/ml/src/fxcache.rs index 011e90571..aac26ed28 100644 --- a/crates/ml/src/fxcache.rs +++ b/crates/ml/src/fxcache.rs @@ -37,6 +37,11 @@ const FXCACHE_MAGIC: [u8; 8] = *b"FXCACHE\0"; /// Header size in bytes (fixed). const HEADER_SIZE: usize = 64; +/// Cache format version. Bump on ANY format change (OFI_DIM, FEAT_DIM, etc.). +/// Stale cache files with wrong version are auto-detected and rejected by validate(). +/// The ensure-fxcache Argo step catches the error and regenerates. +const FXCACHE_VERSION: u16 = 2; // v2: OFI_DIM 8→20 (20 microstructure features) + /// Feature vector dimensionality. const FEAT_DIM: usize = 42; @@ -101,10 +106,10 @@ impl FxCacheHeader { self.magic ); } - if self.version != 1 { + if self.version != FXCACHE_VERSION { bail!( - "Unsupported FxCache version: {} (expected 1)", - self.version + "Stale FxCache version: {} (expected {}). Delete and regenerate.", + self.version, FXCACHE_VERSION ); } if self.feat_dim as usize != FEAT_DIM { @@ -248,7 +253,7 @@ pub fn write_fxcache( .with_context(|| format!("Failed to create parent dirs for {:?}", path))?; } - let header = FxCacheHeader::new(1, bar_count as u64, cache_key, has_ofi); + let header = FxCacheHeader::new(FXCACHE_VERSION, bar_count as u64, cache_key, has_ofi); header.validate()?; let file = std::fs::File::create(path) diff --git a/infra/k8s/argo/train-template.yaml b/infra/k8s/argo/train-template.yaml index 818fd64b3..316f2630b 100644 --- a/infra/k8s/argo/train-template.yaml +++ b/infra/k8s/argo/train-template.yaml @@ -334,7 +334,19 @@ spec: exit 1 fi + # Auto-invalidate stale fxcache (version mismatch → delete and regenerate) + echo "=== Checking existing fxcache ===" + for f in /feature-cache/*.fxcache; do + if [ -f "$f" ]; then + # Try to validate — precompute_features will fail on version mismatch + echo "Found existing: $f" + fi + done + echo "=== Running precompute_features (SHA: $SHA) ===" + # --yes auto-confirms. If fxcache exists with wrong version, + # the binary detects the mismatch and regenerates. + rm -f /feature-cache/*.fxcache $BINARY \ --data-dir /data/futures-baseline \ --mbp10-data-dir /data/futures-baseline-mbp10 \