From 98a81981ac96c4be97b670d3b4a337c0ea826782 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Fri, 8 May 2026 13:09:21 +0200 Subject: [PATCH] fix(build-infra): cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP across 6 crates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per pearl_build_rs_rerun_if_env_changed, every std::env::var() must be paired with cargo:rerun-if-env-changed. Task #321 fixed crates/ml/build.rs (commit e3d082968) but missed 6 sibling build.rs files. Each reads CUDA_COMPUTE_CAP without registering the rerun directive, so cargo sees no env-change between e.g. SM 89 (L40S) → SM 90 (H100) workflow re-submissions and cache-hits the wrong-arch cubin from the previous run. At runtime, the H100 fails to load the SM 89 cubin with CUDA_ERROR_NO_BINARY_FOR_GPU on rmsnorm — exactly what killed train-multi-seed-vlv8c (commit 0371d6a76, post-Class-B chain). Files (all add `println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP")` just before the env::var() read): - crates/ml-dqn/build.rs (rmsnorm — root cause of vlv8c failure) - crates/ml-ensemble/build.rs - crates/ml-explainability/build.rs - crates/ml-ppo/build.rs - crates/ml-supervised/build.rs - crates/ml-core/build.rs Atomic single commit per feedback_no_partial_refactor. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/ml-core/build.rs | 1 + crates/ml-dqn/build.rs | 8 +++++++- crates/ml-ensemble/build.rs | 1 + crates/ml-explainability/build.rs | 1 + crates/ml-ppo/build.rs | 1 + crates/ml-supervised/build.rs | 1 + 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/ml-core/build.rs b/crates/ml-core/build.rs index 22c156cd3..ad5a0afaa 100644 --- a/crates/ml-core/build.rs +++ b/crates/ml-core/build.rs @@ -29,6 +29,7 @@ fn main() { println!("cargo:rerun-if-changed={}", common_header_path.display()); // Detect GPU architecture from env or default to sm_80 + println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP"); let cuda_compute_cap = std::env::var("CUDA_COMPUTE_CAP").unwrap_or_else(|_| "80".to_string()); let arch = format!("sm_{cuda_compute_cap}"); diff --git a/crates/ml-dqn/build.rs b/crates/ml-dqn/build.rs index 74486d572..853c774a7 100644 --- a/crates/ml-dqn/build.rs +++ b/crates/ml-dqn/build.rs @@ -21,7 +21,13 @@ fn main() { println!("cargo:rerun-if-changed={}", common_header_path.display()); - // Detect GPU architecture from env or default to sm_80 + // Detect GPU architecture from env or default to sm_80. + // CRITICAL: pair env::var() with rerun-if-env-changed per + // pearl_build_rs_rerun_if_env_changed, otherwise sccache + cubin caches + // hit-on-SHA across arch changes (e.g., SM 89 L40S → SM 90 H100), and + // training fails at runtime with CUDA_ERROR_NO_BINARY_FOR_GPU on rmsnorm + // cubin load (commit 0371d6a76 on H100, post-Class-B chain). + println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP"); let cuda_compute_cap = std::env::var("CUDA_COMPUTE_CAP").unwrap_or_else(|_| "80".to_string()); let arch = format!("sm_{cuda_compute_cap}"); diff --git a/crates/ml-ensemble/build.rs b/crates/ml-ensemble/build.rs index 654739587..90a92d514 100644 --- a/crates/ml-ensemble/build.rs +++ b/crates/ml-ensemble/build.rs @@ -13,6 +13,7 @@ fn main() { let kernel_dir = Path::new("src"); // Detect GPU architecture from env or default to sm_80 + println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP"); let cuda_compute_cap = std::env::var("CUDA_COMPUTE_CAP").unwrap_or_else(|_| "80".to_string()); let arch = format!("sm_{cuda_compute_cap}"); diff --git a/crates/ml-explainability/build.rs b/crates/ml-explainability/build.rs index 51c1765d0..799dbf628 100644 --- a/crates/ml-explainability/build.rs +++ b/crates/ml-explainability/build.rs @@ -13,6 +13,7 @@ fn main() { let kernel_dir = Path::new("src"); // Detect GPU architecture from env or default to sm_80 (matches crates/ml/build.rs). + println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP"); let cuda_compute_cap = std::env::var("CUDA_COMPUTE_CAP").unwrap_or_else(|_| "80".to_string()); let arch = format!("sm_{cuda_compute_cap}"); diff --git a/crates/ml-ppo/build.rs b/crates/ml-ppo/build.rs index 1da83cbe8..6c044ccb2 100644 --- a/crates/ml-ppo/build.rs +++ b/crates/ml-ppo/build.rs @@ -29,6 +29,7 @@ fn main() { println!("cargo:rerun-if-changed={}", common_header_path.display()); // Detect GPU architecture from env or default to sm_80 + println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP"); let cuda_compute_cap = std::env::var("CUDA_COMPUTE_CAP").unwrap_or_else(|_| "80".to_string()); let arch = format!("sm_{cuda_compute_cap}"); diff --git a/crates/ml-supervised/build.rs b/crates/ml-supervised/build.rs index dd1f05508..ef2abb27e 100644 --- a/crates/ml-supervised/build.rs +++ b/crates/ml-supervised/build.rs @@ -25,6 +25,7 @@ fn main() { let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); // Detect GPU architecture from env or default to sm_80 (L40S / A100). + println!("cargo:rerun-if-env-changed=CUDA_COMPUTE_CAP"); let cuda_compute_cap = std::env::var("CUDA_COMPUTE_CAP").unwrap_or_else(|_| "80".to_string()); let arch = format!("sm_{cuda_compute_cap}");