From c47aa2069b13ff01e1ae7026a88ef3ced65a02d2 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Thu, 10 Sep 2026 13:51:12 -0500 Subject: [PATCH 1/8] reenables macoos --- .github/workflows/merge.yaml | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index e2ee420..ba73fa1 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -35,31 +35,12 @@ jobs: platform_matrix: uses: NWChemEx/.github/.github/workflows/platform_matrix.yaml@master - # SCF has a known, tracked, macOS-only segfault (see - # scf-macos-pybind11-segfault.md) -- skip publishing a macOS wheel until - # it's fixed, rather than ship a broken one. Filters platform_matrix's - # release_matrix down to ubuntu-latest only; drop this job and go back to - # consuming platform_matrix.outputs.release_matrix directly once macOS is - # re-enabled. - filter_release_matrix: - needs: platform_matrix - runs-on: ubuntu-latest - outputs: - release_matrix: ${{ steps.filter.outputs.release_matrix }} - steps: - - id: filter - shell: bash - run: | - filtered=$(echo '${{ needs.platform_matrix.outputs.release_matrix }}' \ - | jq -c '[.[] | select(.os != "macos-14")]') - echo "release_matrix=$filtered" >> "$GITHUB_OUTPUT" - build_pypi_dist: - needs: [tag-commit, filter_release_matrix] + needs: [tag-commit, platform_matrix] strategy: fail-fast: false matrix: - include: ${{ fromJSON(needs.filter_release_matrix.outputs.release_matrix) }} + include: ${{ fromJSON(needs.platform_matrix.outputs.release_matrix) }} runs-on: ${{ matrix.os }} steps: - name: Build PyPI Distribution From 7d0f6f96b778d77f7f36f0b0ba1fce5546281fa7 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Fri, 11 Sep 2026 14:59:01 -0500 Subject: [PATCH 2/8] Ignore every build tree in the license check, not just build/ .gitignore already uses `build*/`, so a second tree (build-debug/, build2/, a renamed one) is invisible to git but still walked by license-eye, which matched only the literal name `build`. On a configured tree that is gigabytes of CMake/FetchContent output per commit, and the walk fails outright when a concurrent build mutates it mid-scan. Co-Authored-By: Claude Opus 5 --- .licenserc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.licenserc.yaml b/.licenserc.yaml index da06fad..224f16e 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -24,6 +24,6 @@ header: - src/scf/common/ - src/scf/scf/ - LICENSE - - build + - build* comment: never From c01ddf4227ddbd6f1ec591637dbe54a669de6e84 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Fri, 11 Sep 2026 14:59:05 -0500 Subject: [PATCH 3/8] test the new setup --- .github/workflows/wheel_dryrun.yaml | 104 ++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 .github/workflows/wheel_dryrun.yaml diff --git a/.github/workflows/wheel_dryrun.yaml b/.github/workflows/wheel_dryrun.yaml new file mode 100644 index 0000000..686ff53 --- /dev/null +++ b/.github/workflows/wheel_dryrun.yaml @@ -0,0 +1,104 @@ +# Copyright 2026 NWChemEx-Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Manually exercises the PyPI wheel build without publishing anything. +# +# merge.yaml's build_pypi_dist job only runs on push-to-master, so the wheel +# build cannot be tested from a pull request -- which is how SCF's macOS leg +# went from the CI migration (PR #64) to now without ever executing once. It +# also cannot be tested cheaply: deploy_to_pypi has `needs: build_pypi_dist`, +# so a failing macOS leg skips the publish job entirely and blocks the *Linux* +# release too. +# +# This workflow is that missing escape hatch. It runs exactly the same +# build_pypi_dist action with exactly the same inputs as merge.yaml, but has +# no tag-commit dependency and no deploy_to_pypi job, so nothing reaches PyPI +# and no version tag is cut. The wheel comes back as an artifact to install +# and smoke-test by hand. +# +# gh workflow run wheel_dryrun.yaml --ref +# +# (workflow_dispatch works from a non-default branch as long as this file +# exists on that branch.) +name: Wheel Build Dry Run + +on: + workflow_dispatch: + inputs: + platform: + description: "Which release leg(s) to build" + required: true + default: "macos" + type: choice + options: + - macos + - linux + - both + +jobs: + # The matrix has to be computed in its own job: the `matrix` context is not + # available in a job-level `if:`, so filtering legs there would silently + # evaluate to the empty string and skip everything. Same shape as + # merge.yaml's platform_matrix -> build_pypi_dist handoff. + select_legs: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.pick.outputs.matrix }} + steps: + - name: Pick Release Legs + id: pick + shell: bash + run: | + # Mirrors platform_matrix.yaml's release_matrix. Hardcoded rather + # than pulled from that reusable workflow so a single leg can be + # selected; keep in sync if release_matrix changes. + macos='{"os": "macos-14", "cibw_build": "cp312-macosx_arm64"}' + linux='{"os": "ubuntu-latest", "cibw_build": "cp312-manylinux_x86_64"}' + case "${{ inputs.platform }}" in + macos) matrix="[${macos}]" ;; + linux) matrix="[${linux}]" ;; + both) matrix="[${macos}, ${linux}]" ;; + *) echo "unknown platform: ${{ inputs.platform }}" >&2; exit 1 ;; + esac + echo "matrix=${matrix}" >> "$GITHUB_OUTPUT" + echo "Building: ${matrix}" + + build_wheel: + needs: select_legs + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(needs.select_legs.outputs.matrix) }} + runs-on: ${{ matrix.os }} + steps: + # Inputs must stay identical to merge.yaml's build_pypi_dist job, or + # this proves nothing about the real release. build_sdist is the one + # deliberate exception: an sdist is platform-independent and already + # covered by the Linux release leg. + - name: Build PyPI Distribution + uses: NWChemEx/.github/.github/actions/build_pypi_dist@master + with: + cibw_build: ${{ matrix.cibw_build }} + build_sdist: "false" + needs_mpi: "true" + needs_boost: "true" + needs_blas: "true" + needs_openmp: "true" + + - name: Upload Distribution Artifact + uses: actions/upload-artifact@v4 + with: + name: dryrun-dist-${{ matrix.os }} + path: dist/ From ab26b0ed216c7ad7a7191a00c480848f6045e80e Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Fri, 11 Sep 2026 15:00:29 -0500 Subject: [PATCH 4/8] Trigger the wheel dry run on push, not just workflow_dispatch GitHub only exposes a workflow_dispatch workflow once its file exists on the default branch; dispatching from the branch that adds it answers HTTP 404: workflow wheel_dryrun.yaml not found on the default branch which makes dispatch useless for the one job it was added to do -- prove the macOS wheel builds *before* anything lands on master. A push trigger scoped to this branch has no such requirement. A push event carries no inputs, so inputs.platform defaults to macos, the leg this exists to exercise. Co-Authored-By: Claude Opus 5 --- .github/workflows/wheel_dryrun.yaml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheel_dryrun.yaml b/.github/workflows/wheel_dryrun.yaml index 686ff53..87c7e59 100644 --- a/.github/workflows/wheel_dryrun.yaml +++ b/.github/workflows/wheel_dryrun.yaml @@ -35,6 +35,15 @@ name: Wheel Build Dry Run on: + # workflow_dispatch alone is not enough to bootstrap this: GitHub only + # exposes a dispatchable workflow once the file exists on the *default* + # branch, so `gh workflow run wheel_dryrun.yaml --ref ` answers + # "not found on the default branch" until this lands on master. The push + # trigger is what makes it usable from the branch that is developing it. + # Narrow it (or drop it) once this is on master and dispatch works. + push: + branches: + - get_macos_on_pypi workflow_dispatch: inputs: platform: @@ -66,7 +75,9 @@ jobs: # selected; keep in sync if release_matrix changes. macos='{"os": "macos-14", "cibw_build": "cp312-macosx_arm64"}' linux='{"os": "ubuntu-latest", "cibw_build": "cp312-manylinux_x86_64"}' - case "${{ inputs.platform }}" in + # A push event carries no inputs; default that to macOS, + # which is the leg this workflow exists to exercise. + case "${{ inputs.platform || 'macos' }}" in macos) matrix="[${macos}]" ;; linux) matrix="[${linux}]" ;; both) matrix="[${macos}, ${linux}]" ;; From b5296a70eb6f646ffbe57a736acda962883ec9d8 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Fri, 11 Sep 2026 15:04:34 -0500 Subject: [PATCH 5/8] Point the dry run at the .github fix branch Temporary. build_pypi_dist@master currently dies before before_all with "Unsupported bash construct: 'assignment'" -- see the first dry run, 34641892205. Validate the fix here before it lands on .github master, which every repo in the ecosystem consumes at @master. Co-Authored-By: Claude Opus 5 --- .github/workflows/wheel_dryrun.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheel_dryrun.yaml b/.github/workflows/wheel_dryrun.yaml index 87c7e59..6ab57b0 100644 --- a/.github/workflows/wheel_dryrun.yaml +++ b/.github/workflows/wheel_dryrun.yaml @@ -98,8 +98,11 @@ jobs: # this proves nothing about the real release. build_sdist is the one # deliberate exception: an sdist is platform-independent and already # covered by the Linux release leg. + # TEMPORARY: pinned to the branch carrying the cibuildwheel + # SKBUILD_CMAKE_DEFINE quoting fix. Revert to @master once + # NWChemEx/.github# merges, and before this branch is merged. - name: Build PyPI Distribution - uses: NWChemEx/.github/.github/actions/build_pypi_dist@master + uses: NWChemEx/.github/.github/actions/build_pypi_dist@macos_wheel_fixes with: cibw_build: ${{ matrix.cibw_build }} build_sdist: "false" From fbd960ac29edb08de536e2fd1a8fb0d9ec1908f1 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Fri, 11 Sep 2026 15:34:41 -0500 Subject: [PATCH 6/8] Don't capture a structured binding in the grid dispatch lambda AppleClang rejects it: grid_from_integratorxx.cpp:217:32: error: reference to local binding 'molecule' declared in enclosing function 'scf::xc::GridFromIntegratorXX::run_' Capturing a structured binding is C++20 (P1091). GCC implements it, so the Linux release wheel and both Linux dev legs compile this fine. AppleClang on the macos-14 runner does not, and AppleClang is reached only by the wheel build -- cibuildwheel compiles with /usr/bin/clang++, while the macOS dev matrix uses Homebrew clang-18 and gcc-14, both of which implement P1091. So no existing job covers this compiler, and the file has been unbuildable there since it was added in #71. Binding the input to an ordinary reference first sidesteps the rule entirely and compiles under any C++17 compiler. Verified against the failing dry run, 34642262844. Co-Authored-By: Claude Opus 5 --- cxx/src/scf/xc/grid_from_integratorxx.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cxx/src/scf/xc/grid_from_integratorxx.cpp b/cxx/src/scf/xc/grid_from_integratorxx.cpp index 64a2c6d..376b3dc 100644 --- a/cxx/src/scf/xc/grid_from_integratorxx.cpp +++ b/cxx/src/scf/xc/grid_from_integratorxx.cpp @@ -161,7 +161,19 @@ MODULE_CTOR(GridFromIntegratorXX) { } MODULE_RUN(GridFromIntegratorXX) { - const auto& [molecule] = pt::unwrap_inputs(inputs); + // Rebound to an ordinary reference because the dispatch lambda below + // captures it. Capturing a structured binding is C++20 (P1091); GCC + // accepts it, but AppleClang -- which is what builds the macOS release + // wheel, since cibuildwheel uses /usr/bin/clang++ -- still rejects it: + // + // error: reference to local binding 'molecule' declared in enclosing + // function 'scf::xc::GridFromIntegratorXX::run_' + // + // The dev matrix cannot catch this. It builds macOS with Homebrew + // clang-18 and gcc-14, both of which implement P1091; AppleClang is + // exercised only by the wheel build. + const auto& [molecule_input] = pt::unwrap_inputs(inputs); + const auto& molecule = molecule_input; const auto& float_type = inputs.at("Float Type").value(); From 959cf4c9dc28b8d2f96ca79ea05c851887164050 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Mon, 14 Sep 2026 09:05:53 -0500 Subject: [PATCH 7/8] Remove the wheel dry-run workflow Scaffolding. It did its job: three runs on a real macos-14 runner found the cibuildwheel SKBUILD_CMAKE_DEFINE quoting defect (which broke wheel builds for every repo in the ecosystem, on both platforms) and an AppleClang compile error in grid_from_integratorxx.cpp that no green job was exercising, then produced a verified macosx_14_0_arm64 wheel. Dropping it also removes the temporary @macos_wheel_fixes pin, so nothing in this branch references anything but NWChemEx/.github@master. Co-Authored-By: Claude Opus 5 --- .github/workflows/wheel_dryrun.yaml | 118 ---------------------------- 1 file changed, 118 deletions(-) delete mode 100644 .github/workflows/wheel_dryrun.yaml diff --git a/.github/workflows/wheel_dryrun.yaml b/.github/workflows/wheel_dryrun.yaml deleted file mode 100644 index 6ab57b0..0000000 --- a/.github/workflows/wheel_dryrun.yaml +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright 2026 NWChemEx-Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Manually exercises the PyPI wheel build without publishing anything. -# -# merge.yaml's build_pypi_dist job only runs on push-to-master, so the wheel -# build cannot be tested from a pull request -- which is how SCF's macOS leg -# went from the CI migration (PR #64) to now without ever executing once. It -# also cannot be tested cheaply: deploy_to_pypi has `needs: build_pypi_dist`, -# so a failing macOS leg skips the publish job entirely and blocks the *Linux* -# release too. -# -# This workflow is that missing escape hatch. It runs exactly the same -# build_pypi_dist action with exactly the same inputs as merge.yaml, but has -# no tag-commit dependency and no deploy_to_pypi job, so nothing reaches PyPI -# and no version tag is cut. The wheel comes back as an artifact to install -# and smoke-test by hand. -# -# gh workflow run wheel_dryrun.yaml --ref -# -# (workflow_dispatch works from a non-default branch as long as this file -# exists on that branch.) -name: Wheel Build Dry Run - -on: - # workflow_dispatch alone is not enough to bootstrap this: GitHub only - # exposes a dispatchable workflow once the file exists on the *default* - # branch, so `gh workflow run wheel_dryrun.yaml --ref ` answers - # "not found on the default branch" until this lands on master. The push - # trigger is what makes it usable from the branch that is developing it. - # Narrow it (or drop it) once this is on master and dispatch works. - push: - branches: - - get_macos_on_pypi - workflow_dispatch: - inputs: - platform: - description: "Which release leg(s) to build" - required: true - default: "macos" - type: choice - options: - - macos - - linux - - both - -jobs: - # The matrix has to be computed in its own job: the `matrix` context is not - # available in a job-level `if:`, so filtering legs there would silently - # evaluate to the empty string and skip everything. Same shape as - # merge.yaml's platform_matrix -> build_pypi_dist handoff. - select_legs: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.pick.outputs.matrix }} - steps: - - name: Pick Release Legs - id: pick - shell: bash - run: | - # Mirrors platform_matrix.yaml's release_matrix. Hardcoded rather - # than pulled from that reusable workflow so a single leg can be - # selected; keep in sync if release_matrix changes. - macos='{"os": "macos-14", "cibw_build": "cp312-macosx_arm64"}' - linux='{"os": "ubuntu-latest", "cibw_build": "cp312-manylinux_x86_64"}' - # A push event carries no inputs; default that to macOS, - # which is the leg this workflow exists to exercise. - case "${{ inputs.platform || 'macos' }}" in - macos) matrix="[${macos}]" ;; - linux) matrix="[${linux}]" ;; - both) matrix="[${macos}, ${linux}]" ;; - *) echo "unknown platform: ${{ inputs.platform }}" >&2; exit 1 ;; - esac - echo "matrix=${matrix}" >> "$GITHUB_OUTPUT" - echo "Building: ${matrix}" - - build_wheel: - needs: select_legs - strategy: - fail-fast: false - matrix: - include: ${{ fromJSON(needs.select_legs.outputs.matrix) }} - runs-on: ${{ matrix.os }} - steps: - # Inputs must stay identical to merge.yaml's build_pypi_dist job, or - # this proves nothing about the real release. build_sdist is the one - # deliberate exception: an sdist is platform-independent and already - # covered by the Linux release leg. - # TEMPORARY: pinned to the branch carrying the cibuildwheel - # SKBUILD_CMAKE_DEFINE quoting fix. Revert to @master once - # NWChemEx/.github# merges, and before this branch is merged. - - name: Build PyPI Distribution - uses: NWChemEx/.github/.github/actions/build_pypi_dist@macos_wheel_fixes - with: - cibw_build: ${{ matrix.cibw_build }} - build_sdist: "false" - needs_mpi: "true" - needs_boost: "true" - needs_blas: "true" - needs_openmp: "true" - - - name: Upload Distribution Artifact - uses: actions/upload-artifact@v4 - with: - name: dryrun-dist-${{ matrix.os }} - path: dist/ From 2c25505054755a91e59e05eef725851e0b5676b1 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Tue, 15 Sep 2026 09:06:16 -0500 Subject: [PATCH 8/8] Re-trigger CI against the rebuilt ecosystem wheels The last CI run on this branch predates the ecosystem config-dependency rollout finishing (NWXCMake 0.2.3 + rebuilt pluginplay/utilities/wtf/ tensorwrapper/chemist/simde). Empty commit, nothing else.