From 4b0eddb282bcc2b7f3dca27d3e4e238d6e5fc258 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Tue, 5 May 2026 22:39:54 -0400 Subject: [PATCH 1/4] feat: add fp-stability command for Verrou-based FP instability testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds ./mfc.sh fp-stability — a persistent floating-point stability test suite using Verrou's random IEEE-754 rounding mode. For each registered test case the runner: 1. Generates initial conditions via pre_process 2. Runs simulation once with --rounding-mode=nearest (reference) 3. Runs simulation N times with --rounding-mode=random 4. Reports max L-inf deviation vs threshold (PASS/FAIL) Two cases probe known ill-conditioning in MFC: - sod_strong: 1-D Sod p_L/p_R=100,000 — HLLC xi-factor cancellation (s_L - vel_L)/(s_L - s_S) near sonic contact - water_stiffened: 1-D water shock pi_inf=4046 — pressure recovery p=(E-pi_inf)/gamma loses ~4 decimal digits on low-pressure side Requires a Verrou-enabled Valgrind at $VERROU_HOME/bin/valgrind (default: $HOME/.local/verrou). Silently skips if not found. Binaries are auto-discovered from build/install/ or passed explicitly. --- .gitignore | 1 + .../cases/sod_strong/pre_process.inp | 33 +++ .../cases/sod_strong/simulation.inp | 29 ++ .../cases/water_stiffened/pre_process.inp | 33 +++ .../cases/water_stiffened/simulation.inp | 29 ++ toolchain/main.py | 4 + toolchain/mfc/cli/commands.py | 60 +++++ toolchain/mfc/fp_stability.py | 253 ++++++++++++++++++ 8 files changed, 442 insertions(+) create mode 100644 tests/fp_stability/cases/sod_strong/pre_process.inp create mode 100644 tests/fp_stability/cases/sod_strong/simulation.inp create mode 100644 tests/fp_stability/cases/water_stiffened/pre_process.inp create mode 100644 tests/fp_stability/cases/water_stiffened/simulation.inp create mode 100644 toolchain/mfc/fp_stability.py diff --git a/.gitignore b/.gitignore index aba54411e1..b0fbea5382 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ docs/documentation/parameters.md /tests/*/** !/tests/*/golden.txt !/tests/*/golden-metadata.txt +!/tests/fp_stability/** # NVIDIA Nsight Compute *.nsys-rep diff --git a/tests/fp_stability/cases/sod_strong/pre_process.inp b/tests/fp_stability/cases/sod_strong/pre_process.inp new file mode 100644 index 0000000000..33693f3d58 --- /dev/null +++ b/tests/fp_stability/cases/sod_strong/pre_process.inp @@ -0,0 +1,33 @@ +&user_inputs +x_domain%beg = 0.0 +x_domain%end = 1.0 +m = 24 +n = 0 +p = 0 +t_step_start = 0 +num_patches = 2 +model_eqns = 2 +num_fluids = 1 +mpp_lim = F +weno_order = 5 +bc_x%beg = -3 +bc_x%end = -3 +precision = 2 +parallel_io = F +patch_icpp(1)%geometry = 1 +patch_icpp(1)%x_centroid = 0.25 +patch_icpp(1)%length_x = 0.5 +patch_icpp(1)%vel(1) = 0.0 +patch_icpp(1)%pres = 1000.0 +patch_icpp(1)%alpha_rho(1) = 10.0 +patch_icpp(1)%alpha(1) = 1.0 +patch_icpp(2)%geometry = 1 +patch_icpp(2)%x_centroid = 0.75 +patch_icpp(2)%length_x = 0.5 +patch_icpp(2)%vel(1) = 0.0 +patch_icpp(2)%pres = 0.01 +patch_icpp(2)%alpha_rho(1) = 0.01 +patch_icpp(2)%alpha(1) = 1.0 +fluid_pp(1)%gamma = 2.5000000000000004 +fluid_pp(1)%pi_inf = 0.0 +&end/ diff --git a/tests/fp_stability/cases/sod_strong/simulation.inp b/tests/fp_stability/cases/sod_strong/simulation.inp new file mode 100644 index 0000000000..5e3091e668 --- /dev/null +++ b/tests/fp_stability/cases/sod_strong/simulation.inp @@ -0,0 +1,29 @@ +&user_inputs +run_time_info = F +x_domain%beg = 0.0 +x_domain%end = 1.0 +m = 24 +n = 0 +p = 0 +dt = 0.0001 +t_step_start = 0 +t_step_stop = 5 +t_step_save = 5 +model_eqns = 2 +num_fluids = 1 +mpp_lim = F +mixture_err = F +time_stepper = 3 +weno_order = 5 +weno_eps = 1e-16 +riemann_solver = 2 +wave_speeds = 1 +avg_state = 2 +bc_x%beg = -3 +bc_x%end = -3 +precision = 2 +prim_vars_wrt = T +parallel_io = F +fluid_pp(1)%gamma = 2.5000000000000004 +fluid_pp(1)%pi_inf = 0.0 +&end/ diff --git a/tests/fp_stability/cases/water_stiffened/pre_process.inp b/tests/fp_stability/cases/water_stiffened/pre_process.inp new file mode 100644 index 0000000000..986eb0f81f --- /dev/null +++ b/tests/fp_stability/cases/water_stiffened/pre_process.inp @@ -0,0 +1,33 @@ +&user_inputs +x_domain%beg = 0.0 +x_domain%end = 1.0 +m = 24 +n = 0 +p = 0 +t_step_start = 0 +num_patches = 2 +model_eqns = 2 +num_fluids = 1 +mpp_lim = F +weno_order = 5 +bc_x%beg = -3 +bc_x%end = -3 +precision = 2 +parallel_io = F +patch_icpp(1)%geometry = 1 +patch_icpp(1)%x_centroid = 0.25 +patch_icpp(1)%length_x = 0.5 +patch_icpp(1)%vel(1) = 0.0 +patch_icpp(1)%pres = 100.0 +patch_icpp(1)%alpha_rho(1) = 1.0 +patch_icpp(1)%alpha(1) = 1.0 +patch_icpp(2)%geometry = 1 +patch_icpp(2)%x_centroid = 0.75 +patch_icpp(2)%length_x = 0.5 +patch_icpp(2)%vel(1) = 0.0 +patch_icpp(2)%pres = 0.1 +patch_icpp(2)%alpha_rho(1) = 1.0 +patch_icpp(2)%alpha(1) = 1.0 +fluid_pp(1)%gamma = 0.195312500 +fluid_pp(1)%pi_inf = 4046.31 +&end/ diff --git a/tests/fp_stability/cases/water_stiffened/simulation.inp b/tests/fp_stability/cases/water_stiffened/simulation.inp new file mode 100644 index 0000000000..06a8c554ea --- /dev/null +++ b/tests/fp_stability/cases/water_stiffened/simulation.inp @@ -0,0 +1,29 @@ +&user_inputs +run_time_info = F +x_domain%beg = 0.0 +x_domain%end = 1.0 +m = 24 +n = 0 +p = 0 +dt = 5e-5 +t_step_start = 0 +t_step_stop = 5 +t_step_save = 5 +model_eqns = 2 +num_fluids = 1 +mpp_lim = F +mixture_err = T +time_stepper = 3 +weno_order = 5 +weno_eps = 1e-16 +riemann_solver = 2 +wave_speeds = 1 +avg_state = 2 +bc_x%beg = -3 +bc_x%end = -3 +precision = 2 +prim_vars_wrt = T +parallel_io = F +fluid_pp(1)%gamma = 0.195312500 +fluid_pp(1)%pi_inf = 4046.31 +&end/ diff --git a/toolchain/main.py b/toolchain/main.py index fe3c0ed630..f7b1fa9e70 100644 --- a/toolchain/main.py +++ b/toolchain/main.py @@ -198,6 +198,10 @@ def __run(): from mfc import params_cmd params_cmd.params() + elif cmd == "fp-stability": + from mfc import fp_stability + + fp_stability.fp_stability() if __name__ == "__main__": diff --git a/toolchain/mfc/cli/commands.py b/toolchain/mfc/cli/commands.py index 207ab08dbf..5f240d620b 100644 --- a/toolchain/mfc/cli/commands.py +++ b/toolchain/mfc/cli/commands.py @@ -900,6 +900,65 @@ include_common=["targets", "mfc_config", "jobs", "verbose", "debug_log"], ) +FP_STABILITY_COMMAND = Command( + name="fp-stability", + help="Run floating-point stability tests using Verrou.", + description=( + "Runs each registered test case N times under Verrou's random IEEE-754 " + "rounding mode and compares against a nearest-rounding reference run. " + "Reports the max L∞ deviation and PASS/FAIL against per-case thresholds.\n\n" + "Requires a Verrou-enabled Valgrind at $VERROU_HOME/bin/valgrind " + "(defaults to $HOME/.local/verrou). The simulation and pre_process " + "binaries must be serial (no-MPI, no-GPU) debug builds.\n\n" + "Current test cases:\n" + " sod_strong 1-D Sod p_L/p_R=100,000 — HLLC xi-factor cancellation\n" + " water_stiffened 1-D water shock (pi_inf=4046) — pressure-recovery cancellation\n" + ), + include_common=["mfc_config", "verbose", "debug_log"], + arguments=[ + Argument( + name="sim-binary", + help="Path to a serial simulation binary (debug, no-MPI). Auto-discovered from build/install/ if omitted.", + default=None, + metavar="PATH", + ), + Argument( + name="pre-binary", + help="Path to a serial pre_process binary (no-MPI). Auto-discovered from build/install/ if omitted.", + default=None, + metavar="PATH", + ), + Argument( + name="verrou-binary", + help="Path to a Verrou-enabled valgrind binary. Defaults to $VERROU_HOME/bin/valgrind or $HOME/.local/verrou/bin/valgrind.", + default=None, + metavar="PATH", + ), + Argument( + name="samples", + short="N", + help="Number of random-rounding simulation runs per test case.", + type=int, + default=5, + metavar="N", + ), + ], + examples=[ + Example("./mfc.sh fp-stability", "Auto-discover binaries and run all cases"), + Example( + "./mfc.sh fp-stability --sim-binary build/install/abc123/bin/simulation", + "Specify simulation binary explicitly", + ), + Example("./mfc.sh fp-stability -N 10", "Run 10 random-rounding samples per case"), + ], + key_options=[ + ("--sim-binary PATH", "Serial simulation binary (debug, no-MPI)"), + ("--pre-binary PATH", "Serial pre_process binary"), + ("--verrou-binary PATH", "Verrou-enabled valgrind"), + ("-N, --samples N", "Random-rounding samples per case (default: 5)"), + ], +) + VIZ_COMMAND = Command( name="viz", help="Visualize post-processed MFC output.", @@ -1372,6 +1431,7 @@ BENCH_DIFF_COMMAND, COUNT_COMMAND, COUNT_DIFF_COMMAND, + FP_STABILITY_COMMAND, ], common_sets=[ COMMON_TARGETS, diff --git a/toolchain/mfc/fp_stability.py b/toolchain/mfc/fp_stability.py new file mode 100644 index 0000000000..3d907a4e81 --- /dev/null +++ b/toolchain/mfc/fp_stability.py @@ -0,0 +1,253 @@ +""" +Floating-point stability test suite using Verrou. + +Each test case runs the simulation N times under random IEEE-754 rounding +and measures the max deviation from a nearest-rounding reference. Cases +that exceed their threshold are reported as FAIL. + +Requires: + - Verrou-enabled Valgrind at $VERROU_HOME/bin/valgrind + (default: $HOME/.local/verrou) + - A serial (no-MPI, no-GPU) simulation binary + - A serial pre_process binary (to generate initial conditions) + +Usage: + ./mfc.sh fp-stability --sim-binary PATH --pre-binary PATH + ./mfc.sh fp-stability # auto-discovers newest installed binaries +""" + +import glob +import os +import shutil +import subprocess +import sys +import tempfile +import time + +from .common import MFC_ROOT_DIR, MFCException +from .printer import cons +from .state import ARG + +CASES_DIR = os.path.join(MFC_ROOT_DIR, "tests", "fp_stability", "cases") + +# Each case: +# name - subdirectory under CASES_DIR +# description - human-readable purpose +# compare - list of D/ filenames to compare (relative to save step) +# threshold - max L∞ deviation allowed (in conserved-variable units) +# ill_cond - description of the known ill-conditioning +CASES = [ + { + "name": "sod_strong", + "description": "1-D Sod, p_L/p_R=100,000, ideal gas", + "compare": ["cons.1.00.000005.dat", "cons.3.00.000005.dat"], + "threshold": 1e-10, + "ill_cond": "HLLC xi factor: (s_L - vel_L)/(s_L - s_S) cancels near sonic contact", + }, + { + "name": "water_stiffened", + "description": "1-D water shock, stiffened EOS (pi_inf=4046)", + "compare": ["cons.1.00.000005.dat", "prim.3.00.000005.dat"], + "threshold": 1e-10, + "ill_cond": "Pressure recovery: p = (E - pi_inf)/gamma loses ~4 digits (pi_inf/p_right ~ 40,000)", + }, +] + + +def _find_verrou() -> str: + verrou_home = os.environ.get("VERROU_HOME", os.path.join(os.path.expanduser("~"), ".local", "verrou")) + candidate = os.path.join(verrou_home, "bin", "valgrind") + if os.path.isfile(candidate) and os.access(candidate, os.X_OK): + return candidate + fallback = shutil.which("valgrind") + return fallback or "" + + +def _find_binary(name: str) -> str: + install_dir = os.path.join(os.getcwd(), "build", "install") + candidates = glob.glob(os.path.join(install_dir, "*", "bin", name)) + if not candidates: + return "" + return max(candidates, key=os.path.getmtime) + + +def _exclude_args(exclude_file: str) -> list: + """Return --exclude flag if a verrou exclusion file is provided.""" + if exclude_file and os.path.isfile(exclude_file): + return [f"--exclude={exclude_file}"] + return [] + + +def _run_preprocess(pp_bin: str, case_dir: str, work_dir: str): + """Generate initial conditions in work_dir.""" + shutil.copy2(os.path.join(case_dir, "pre_process.inp"), work_dir) + with open(os.path.join(work_dir, "pre.log"), "w") as f: + result = subprocess.run( + [pp_bin], + cwd=work_dir, + stdout=f, + stderr=subprocess.STDOUT, + check=False, + ) + if result.returncode != 0: + raise MFCException(f"pre_process failed (rc={result.returncode}). See {work_dir}/pre.log") + + +def _run_simulation_verrou( + verrou_bin: str, + sim_bin: str, + work_dir: str, + run_dir: str, + rounding_mode: str, + exclude_args: list, +): + """Copy IC files into a fresh tmpdir, run simulation under verrou, collect D/ output.""" + with tempfile.TemporaryDirectory(prefix="mfc-fps-") as tmpdir: + # Copy static inputs + for fname in ["simulation.inp", "indices.dat", "pre_time_data.dat", "io_time_data.dat"]: + src = os.path.join(work_dir, fname) + if os.path.exists(src): + shutil.copy2(src, tmpdir) + + # Copy ICs (p_all_ic → p_all) + shutil.copytree( + os.path.join(work_dir, "p_all"), + os.path.join(tmpdir, "p_all"), + ) + os.makedirs(os.path.join(tmpdir, "D")) + + log_path = os.path.join(run_dir, "verrou.log") + cmd = [ + verrou_bin, + "--tool=verrou", + f"--rounding-mode={rounding_mode}", + "--error-limit=no", + f"--log-file={log_path}", + *exclude_args, + sim_bin, + ] + + with open(os.path.join(run_dir, "sim.out"), "w") as f: + result = subprocess.run(cmd, cwd=tmpdir, stdout=f, stderr=subprocess.STDOUT, check=False) + + if result.returncode != 0: + raise MFCException(f"simulation (rounding={rounding_mode}) exited {result.returncode}. See {run_dir}/sim.out") + + # Collect D/ outputs + os.makedirs(run_dir, exist_ok=True) + d_src = os.path.join(tmpdir, "D") + for fn in os.listdir(d_src): + shutil.copy2(os.path.join(d_src, fn), run_dir) + + +def _max_diff(ref_dir: str, run_dir: str, compare_files: list) -> float: + try: + import numpy as np + except ImportError: + raise MFCException("numpy is required for fp-stability comparison") + + total = 0.0 + for fname in compare_files: + ref_path = os.path.join(ref_dir, fname) + run_path = os.path.join(run_dir, fname) + if not os.path.exists(ref_path): + raise MFCException(f"Reference output missing: {ref_path}") + if not os.path.exists(run_path): + raise MFCException(f"Run output missing: {run_path}") + ref = np.loadtxt(ref_path)[:, 1] + run = np.loadtxt(run_path)[:, 1] + total = max(total, float(np.max(np.abs(ref - run)))) + return total + + +def _run_case(case: dict, verrou_bin: str, sim_bin: str, pp_bin: str, n_samples: int) -> bool: + """Run one stability test case. Returns True if the case passes.""" + name = case["name"] + threshold = case["threshold"] + compare = case["compare"] + case_dir = os.path.join(CASES_DIR, name) + + cons.print(f"[bold]{name}[/bold]: {case['description']}") + cons.indent() + cons.print(f" ill-conditioning: {case['ill_cond']}") + cons.print(f" threshold: {threshold:.0e}") + + work_dir = tempfile.mkdtemp(prefix=f"mfc-fps-{name}-") + try: + # Generate ICs + cons.print(" [dim]running pre_process...[/dim]") + shutil.copy2(os.path.join(case_dir, "simulation.inp"), work_dir) + _run_preprocess(pp_bin, case_dir, work_dir) + + # Reference run (nearest rounding — deterministic baseline) + ref_dir = os.path.join(work_dir, "ref") + os.makedirs(ref_dir) + cons.print(" [dim]reference run (rounding=nearest)...[/dim]") + _run_simulation_verrou(verrou_bin, sim_bin, work_dir, ref_dir, "nearest", []) + + # Random-rounding samples + max_dev = 0.0 + cons.print(f" [dim]random-rounding runs (N={n_samples})...[/dim]") + for i in range(n_samples): + run_dir = os.path.join(work_dir, f"run_{i:02d}") + os.makedirs(run_dir) + _run_simulation_verrou(verrou_bin, sim_bin, work_dir, run_dir, "random", []) + dev = _max_diff(ref_dir, run_dir, compare) + max_dev = max(max_dev, dev) + + passed = max_dev <= threshold + + tag = "[bold green]PASS[/bold green]" if passed else "[bold red]FAIL[/bold red]" + cons.print(f" {tag} max_dev={max_dev:.3e} threshold={threshold:.0e}") + finally: + shutil.rmtree(work_dir, ignore_errors=True) + + cons.unindent() + cons.print() + return passed + + +def fp_stability(): + verrou_bin = ARG("verrou_binary") or _find_verrou() + if not verrou_bin or not os.path.isfile(verrou_bin): + cons.print("[bold yellow]SKIP[/bold yellow]: verrou not found. Install at $HOME/.local/verrou or set VERROU_HOME.") + sys.exit(0) + + sim_bin = ARG("sim_binary") or _find_binary("simulation") + if not sim_bin or not os.path.isfile(sim_bin): + raise MFCException("simulation binary not found. Build with --debug --no-mpi, or pass --sim-binary.") + + pp_bin = ARG("pre_binary") or _find_binary("pre_process") + if not pp_bin or not os.path.isfile(pp_bin): + raise MFCException("pre_process binary not found. Build with --no-mpi, or pass --pre-binary.") + + n_samples = ARG("samples") or 5 + + cons.print() + cons.print("[bold]MFC Floating-Point Stability Suite[/bold]") + cons.print(f" verrou: {verrou_bin}") + cons.print(f" simulation: {sim_bin}") + cons.print(f" pre_process: {pp_bin}") + cons.print(f" samples: {n_samples}") + cons.print() + + start = time.time() + results = [] + for case in CASES: + try: + ok = _run_case(case, verrou_bin, sim_bin, pp_bin, n_samples) + except MFCException as exc: + cons.print(f" [bold red]ERROR[/bold red]: {exc}") + ok = False + results.append((case["name"], ok)) + + elapsed = time.time() - start + n_pass = sum(1 for _, ok in results if ok) + n_fail = len(results) - n_pass + + cons.print(f"[bold]Results[/bold] ({elapsed:.0f}s): [green]{n_pass} passed[/green] [red]{n_fail} failed[/red]") + for name, ok in results: + mark = "[green]✓[/green]" if ok else "[red]✗[/red]" + cons.print(f" {mark} {name}") + + sys.exit(0 if n_fail == 0 else 1) From ae917e12a8e5fc2d4095931f47654f0c5e944fa5 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Tue, 5 May 2026 22:46:02 -0400 Subject: [PATCH 2/4] ci: add weekly FP stability workflow using Verrou --- .github/workflows/fp-stability.yml | 83 ++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 .github/workflows/fp-stability.yml diff --git a/.github/workflows/fp-stability.yml b/.github/workflows/fp-stability.yml new file mode 100644 index 0000000000..5b98f1f261 --- /dev/null +++ b/.github/workflows/fp-stability.yml @@ -0,0 +1,83 @@ +name: FP Stability + +# Runs the Verrou-based floating-point stability suite. +# +# What it tests (./mfc.sh fp-stability): +# sod_strong 1-D Sod shock, p_L/p_R=100,000, ideal gas +# 25 cells, 5 steps, WENO5 + HLLC +# Compares density & energy vs. threshold 1e-10 +# Probes: HLLC xi-factor cancellation near sonic contact +# (s_L - vel_L)/(s_L - s_S) when s_L ≈ s_S +# +# water_stiffened 1-D water shock, stiffened EOS (pi_inf=4046) +# 25 cells, 5 steps, WENO5 + HLLC +# Compares density & pressure vs. threshold 1e-10 +# Probes: pressure-recovery cancellation p=(E-pi_inf)/gamma +# loses ~4 decimal digits when pi_inf/p_right ~ 40,000 +# +# For each case: 1 nearest-rounding reference run + N random-rounding runs. +# PASS if max L∞ deviation across all N samples stays below threshold. +# +# Verrou (Valgrind 3.26.0 + edf-hpc/verrou@a58d434) is built once and cached. +# Build takes ~20 min uncached; cached runs restore in ~30 s. + +on: + schedule: + - cron: '0 5 * * 1' # Weekly Monday 5 AM UTC + workflow_dispatch: # Manual trigger + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + fp-stability: + name: Floating-Point Stability (Verrou) + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Cache Verrou + id: cache-verrou + uses: actions/cache@v4 + with: + path: ~/.local/verrou + key: verrou-a58d434-valgrind-3.26.0-${{ runner.os }} + + - name: Install system dependencies + run: | + sudo apt-get update -y + sudo apt-get install -y \ + build-essential automake python3 libc6-dbg \ + cmake gfortran + + - name: Build Verrou + if: steps.cache-verrou.outputs.cache-hit != 'true' + run: | + cd /tmp + wget -q https://sourceware.org/pub/valgrind/valgrind-3.26.0.tar.bz2 + tar xf valgrind-3.26.0.tar.bz2 + + git clone https://github.com/edf-hpc/verrou.git + git -C verrou checkout a58d434 + + # Merge Verrou into Valgrind source tree and patch + cp -r verrou valgrind-3.26.0/verrou + cd valgrind-3.26.0 + cat verrou/valgrind.*diff | patch -p1 + + ./autogen.sh + ./configure --enable-only64bit --prefix="$HOME/.local/verrou" + make -j"$(nproc)" + make install + + - name: Verify Verrou + run: ~/.local/verrou/bin/valgrind --version + + - name: Build MFC (debug, serial) + run: ./mfc.sh build -t pre_process simulation --no-mpi --debug -j"$(nproc)" + + - name: Run FP Stability Suite + run: ./mfc.sh fp-stability -N 5 From b0951f0060ead5b2b9426c49addc5b545c696777 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Tue, 5 May 2026 22:47:35 -0400 Subject: [PATCH 3/4] ci: trigger fp-stability on every push --- .github/workflows/fp-stability.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/fp-stability.yml b/.github/workflows/fp-stability.yml index 5b98f1f261..57caa40b32 100644 --- a/.github/workflows/fp-stability.yml +++ b/.github/workflows/fp-stability.yml @@ -22,9 +22,8 @@ name: FP Stability # Build takes ~20 min uncached; cached runs restore in ~30 s. on: - schedule: - - cron: '0 5 * * 1' # Weekly Monday 5 AM UTC - workflow_dispatch: # Manual trigger + push: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 5c8eaab38ce8eb3f89715a4eb47e4d7ff518e9be Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Tue, 5 May 2026 22:47:51 -0400 Subject: [PATCH 4/4] ci: remove concurrency group from fp-stability --- .github/workflows/fp-stability.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/fp-stability.yml b/.github/workflows/fp-stability.yml index 57caa40b32..1ead1d5cc8 100644 --- a/.github/workflows/fp-stability.yml +++ b/.github/workflows/fp-stability.yml @@ -25,10 +25,6 @@ on: push: workflow_dispatch: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: fp-stability: name: Floating-Point Stability (Verrou)