SeisSol, from a Spack recipe to a PR

Flow from an old SeisSol easyconfig and a Spack recipe, through a site-named foss-2025a generation, to the next easyconfig and a PR.

The old easyconfig is the next file. Spack names missing deps. The site names the generation.

Parent bump of SeisSol 1.1.4, then companion recipes, then a pull request. Spack is not the file EasyBuild builds.

Parent bump of 1.1.4, then companions, then a PR. Spack is not the file eb builds.

Site stack 2025 selects foss-2025a. Newest-on-develop foss-2026.1 is a different consume.

The generation is a site fact. eb-stack writes the next file. eb still has to run.

Questions

  • When both a Spack package.py and an old easyconfig exist, which eb-stack command writes the next file EasyBuild will build?

  • What does a parent package bump print when ASAGI, easi, or PSpaMM have no candidate on the target generation?

  • What names the toolchain generation: the newest common toolchain, or the site stack the module will load?

  • Which two EasyBuild claims look like checksums or sanity and are not, until the named artifact is the one that was hashed or imported?

What you will be able to do

  1. Given a Spack package and an older easyconfig for the same software, name the parent command, the companion commands, and the command that still has to be eb.

  2. Read a parent bump that exits 1 and say what companion= and re_run= mean, and when the overlay is done.

  3. Name the generation the production stack already built, and say what a foss/2026.1 recipe does on that stack.

  4. Tell a git-config checksum of the wrong tarball from a Python sanity check that imports the EasyBuild name rather than the module.

Before this page

SeisSol 1.3.2 is the tagged release this case used. The EasyBuild robot on develop had SeisSol-1.1.4-foss-2023a.eb. Spack’s seissol recipe stopped at tag 1.3.1. The next EasyBuild file is a bump of 1.1.4 rather than a blank plan of that Spack file. eb-stack ports a recipe and bumps one already split those two jobs. This page is the overlay that came out, the site install, and the PR. The first site build found two defects. The overlay, the site install, and the PR are not a compile.

The parent is the old easyconfig

package inspect --format spack on Spack’s seissol recipe writes a plan and an SBOM. It does not write a .eb. The residuals are tight pins that Spack states and that SeisSol 1.3.2 CMake does not: yaml-cpp@0.6.2, eigen@3.4.0 exact, netcdf-c@4.6:4.8.1. The 1.1.4 easyconfig already used netCDF 4.9.2, above that Spack upper bound. CMake for 1.3.2 asks for Eigen 3.4 or newer and handles yaml-cpp 0.8. Those inspect residuals are Spack conservatism, not SeisSol bounds. package bump of SeisSol-1.1.4-foss-2023a.eb is the parent. Leave out --toolchain-name. The family stays foss. A SeisSol-only bump that exits 0 while ASAGI, easi, or PSpaMM have no foss-2025a candidate is a hole. The parent exits 1 and prints the holes. The text after each companion= is a full eb-stack package command. re_run= is the parent command again. The transcript that follows is a recorded parent bump rather than a description of a PR. Each companion= line is a command that was printed.

Parent bump exits 1; three companion= lines, then re_run=

$ eb-stack package bump \
>   --source SeisSol-1.1.4-foss-2023a.eb \
>   --version 1.3.2 \
>   --toolchain-version 2025a \
>   --package-config seissol.toml \
>   --easyconfigs ROBOT \
>   --out-dir OUT
generation_target=foss-2025a
residual=unresolved-generation-dep ASAGI =1.0
residual=unresolved-generation-dep easi =1.7.0
residual=unresolved-generation-dep PSpaMM =0.3.1
companion=eb-stack package bump --source ASAGI-1.0-foss-2023a.eb --toolchain-name foss --toolchain-version 2025a --version 1.0 --easyconfigs ROBOT --out-dir OUT
companion=eb-stack package bump --source easi-1.3.0-foss-2023a.eb --toolchain-name foss --toolchain-version 2025a --version 1.7.0 --package-config easi.toml --easyconfigs ROBOT --out-dir OUT
companion=eb-stack package plan --package-config pspamm.toml --source py-pspamm/package.py --toolchain-name gfbf --toolchain-version 2025a --easyconfigs ROBOT --out-dir OUT
re_run=eb-stack package bump --source SeisSol-1.1.4-foss-2023a.eb --toolchain-name foss --toolchain-version 2025a --version 1.3.2 --package-config seissol.toml --easyconfigs ROBOT --out-dir OUT
done_when=exit 0
next=eval each companion= line as a shell command, then eval re_run=
Error: unresolved on this generation; run each companion= line, then re_run=

Recorded: eb-stack package bump, 2026-09-11

  1. ASAGI 1.0: the first companion= is package bump of the 2023a recipe.

  2. easi 1.7.0: the second is package bump --version 1.7.0 with the easi package-config. ImpalaJIT is exclude_from_solve. 1.7.0 is Lua-only.

  3. PSpaMM 0.3.1: the third is package plan from the Spack py_pspamm recipe, on gfbf-2025a. PSpaMM has no easyconfig to bump. The package-config sets options.modulename to pypspamm.

First companion=: ASAGI bump exits 0

$ eb-stack package bump --source ASAGI-1.0-foss-2023a.eb --toolchain-name foss --toolchain-version 2025a --version 1.0 --easyconfigs ROBOT --out-dir OUT
generation_target=foss-2025a
done_when=exit 0

Recorded: eb-stack companion ASAGI, 2026-09-11

Second companion=: easi bump exits 0

$ eb-stack package bump --source easi-1.3.0-foss-2023a.eb --toolchain-name foss --toolchain-version 2025a --version 1.7.0 --package-config easi.toml --easyconfigs ROBOT --out-dir OUT
generation_target=foss-2025a
done_when=exit 0

Recorded: eb-stack companion easi, 2026-09-11

Third companion=: PSpaMM plan exits 0

$ eb-stack package plan --package-config pspamm.toml --source py-pspamm/package.py --toolchain-name gfbf --toolchain-version 2025a --easyconfigs ROBOT --out-dir OUT
generation_target=gfbf-2025a
done_when=exit 0

Recorded: eb-stack companion PSpaMM, 2026-09-11

After those three recorded commands, the same parent is re_run=. The overlay is done when that line exits 0 and writes the four .eb files.

re_run= after the three companions; parent exits 0

$ eval "$re_run"
generation_target=foss-2025a
done_when=exit 0
$ ls OUT/*.eb
OUT/ASAGI-1.0-foss-2025a.eb
OUT/PSpaMM-0.3.1-gfbf-2025a.eb
OUT/SeisSol-1.3.2-foss-2025a.eb
OUT/easi-1.7.0-foss-2025a.eb

Recorded: eb-stack package bump re_run, 2026-09-11

seissol.toml stores the inject digest and the local_* names. The digest is not a Spack hash and not a working-tree hash.

[source_checksums]
# inject digest of the recursive git_config archive EasyBuild packed
"seissol-v1.3.2.tar.gz" = "inject"

[easyconfig]
local_host_arch = "hsw"
local_order = "6"
local_equations = "elastic"

EB-SeisSol-1 — Inspect, bump, or plan

For each starting point, name the eb-stack command, or say the work is not eb-stack’s.

  1. spack/packages/seissol/package.py, and SeisSol-1.1.4-foss-2023a.eb already in the robot.

  2. easi-1.3.0-foss-2023a.eb, latest tag v1.7.0, ImpalaJIT gone from CMake.

  3. PSpaMM 0.3.1, Spack package.py, no easyconfig in the robot.

  4. The four .eb files, nobody has run eb yet.

Solution
  1. Bump the existing easyconfig. That is the file EasyBuild will build. Inspect the Spack file for residuals. Do not emit from it.

  2. package bump --version 1.7.0 with the easi package-config. ImpalaJIT is exclude_from_solve. A missing ImpalaJIT on 2025a is not a companion.

  3. package plan from the Spack recipe, on gfbf-2025a. PSpaMM has no easyconfig to bump.

  4. eb, or the site wrapper that is eb on that machine. recipe check is not a build.

The generation is a site fact

The newest common toolchain on develop in September 2026 is foss/2026.1. A first bump onto that generation resolves. It does not load on a node whose production stack is 2025. foss/2025a is the generation that stack is built from. eb -S SeisSol on that login node returns only SeisSol-1.1.4-foss-2023a.eb. A foss/2026.1 recipe asks the robot for a generation the site has not built. --robot will try to compile GCC 15 and the rest of 2026.1 beside the 2025 tree. That compile writes into the user’s prefix and consumes home quota.

Which file loads on the 2025 stack

A login node has just run module load 2025. Which of these four files can eblocalinstall resolve against the modules already on the node?

  1. SeisSol-1.3.2-foss-2026.1.eb

  2. SeisSol-1.3.2-foss-2025a.eb in #26851

  3. SeisSol-1.3.2-foss-2025b.eb

  4. SeisSol-1.3.2-intel-2025a.eb

What happens

(2). foss/2025a is present. 2026.1 is not. 2025b exists as a toolchain module in some listings and is not the generation the 2025 production recipes use. intel is documented for local builds by experienced users, not the default site stack.

The 2025a robot includes Lua 5.4.8 and libxsmm 1.17. easi 1.7.0 provides lmathx via Lua 5.4. A warning states that Lua 5.5 may fail to compile. The companion Lua 5.4.8 recipe that a 2026.1 bump would have added is unnecessary on 2025a.

The site wrapper is the install

The Snellius EasyBuild tutorial loads the site EasyBuild module after module load 2025 and installs with eblocalinstall, not a raw eb plus hand-set --installpath-software. The wrapper writes software and modulefiles under the 2025 prefix:

$ eblocalinstall OUT/ASAGI-1.0-foss-2025a.eb
$ eblocalinstall OUT/PSpaMM-0.3.1-gfbf-2025a.eb
$ eblocalinstall OUT/easi-1.7.0-foss-2025a.eb
$ eblocalinstall OUT/SeisSol-1.3.2-foss-2025a.eb

Those four commands write under:

~/.local/easybuild/RHEL9/2025/software
~/.local/easybuild/RHEL9/2025/modules

Two defects the first build named

The patch that was no longer the patch

The first eblocalinstall failed on ASAGI. EasyBuild hashed the file next to the recipe and compared it to da8c1c8c.... The file on disk hashed to something else. A paste through a narrow terminal had wrapped the patch into a different byte string. The named checksum was still the official ASAGI-1.0_fix-level.h.patch from develop. The file under that name was not that archive. A checksum is a claim about bytes is this failure, at site scale. The repair fetches the upstream patch; hashing the broken file again repairs nothing.

The import that was the EasyBuild name

ASAGI then installed. PSpaMM failed sanity:

Default PythonPackage import

ModuleNotFoundError: No module named 'pspamm'

Recorded: site login node, 2026-09-11

The easyconfig is named PSpaMM. EasyBuild’s PythonPackage imports pspamm. The distribution’s module is pypspamm. The console script is pspamm-generator. The failed check was the one nobody wrote.

options = {'modulename': 'pypspamm'}

That line is the fix. It now lives in the PSpaMM package-config, so the next package plan writes it. A second eblocalinstall then completed PSpaMM, easi 1.7.0, and SeisSol 1.3.2. SeisSol_Release_dhsw_6_elastic --help printed Show this help message. HOST_ARCH=hsw is the CMake default. The recipe stores it as local_host_arch, with local_order and local_equations. local_binary and configopts are formatted from those three names. A site that retargets the arch edits one assignment. The binary runs on the login node and is not zen-tuned.

EB-SeisSol-2 — Which claim failed

Three failures. For each, name the claim that was false, and the smallest change that makes the claim true.

  1. checksums lists the hash of a recursive working tree. EasyBuild git_config hashes the tarball it packed.

  2. sanity_check_commands runs python -c "import pspamm" through the default PythonPackage import.

  3. The recipe toolchain is foss/2026.1. The node has module load 2025 and foss/2025a.

Solution
  1. The checksum named the wrong archive. Inject with eb --inject-checksums on the EasyBuild host, or hash the git_config tarball EasyBuild wrote. Do not keep the working-tree hash.

  2. The import name is pypspamm. Set options = {'modulename': 'pypspamm'}. Leave the pspamm-generator sanity command.

  3. The generation is not on the node. Retarget to foss/2025a. A 2026.1 recipe is a different consume, not a fix of this one.

The overlay the PR names

The overlay is four files on the 2025 generation.

  • ASAGI 1.0, easi 1.7.0, PSpaMM 0.3.1 on gfbf-2025a, SeisSol 1.3.2.

  • The SeisSol checksum is the inject digest of the recursive git_config archive. It lives in the package-config as source_checksums. That digest is neither a Spack hash nor a working-tree hash.

  • eb --check-contrib passed style and SHA256 on those four files.

  • eb --new-pr opened easybuild-easyconfigs#26851 from the HaoZeke fork onto develop. The body names the four files and the Lua 5.4 bound on easi 1.7.0.

  • resolves is the SAT of the 2025a robot plus the overlay.

  • builds is the site wrapper install of those four files.

  • A login-node --help is the sanity the recipe declared, not a TPV run.

  • eb --from-pr 26851 --robot --force rebuilt the same four files in 14 minutes 49 seconds. All results were SUCCESS. That is the report in the PR comment.

What to remember

  • The next file is a bump of the old easyconfig. Inspect Spack for residuals. Do not emit the EasyBuild file from Spack.

  • A parent bump that still needs companions exits 1 and prints companion=. The overlay is done when the parent exits 0.

  • PSpaMM is a package plan on gfbf. easi drops ImpalaJIT in package-config, not in a hand edit.

  • The generation is the one the site module environment already built. Newest-on-develop is a different consume.

  • The site wrapper is the install. Raw eb with hand-set prefixes is a different consume.

  • A checksum names one archive. A PythonPackage import names one module. Neither is the EasyBuild software name.