Skip to content

housekeeping for 4.0 - #483

Merged
ofloveandhate merged 14 commits into
developfrom
chore/housekeeping-for-4.0
Oct 3, 2026
Merged

ofloveandhate merged 14 commits into
developfrom
chore/housekeeping-for-4.0

Conversation

@ofloveandhate

@ofloveandhate ofloveandhate commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Small fixes collected for 4.0, each its own commit, so they can be reviewed and merged in one go instead of one pull request apiece. This description is a running list and grows as commits land.

Changes

  • Every GitHub Action runs on Node 24. GitHub is removing Node 20 from its runners, and recent runs warned about it. Seven actions targeted an old runtime; each moves to its lowest major on Node 24: actions/setup-python v5→v6, conda-incubator/setup-miniconda v3→v4, actions/upload-artifact v5→v6, actions/download-artifact v5→v7 (v6 is still Node 20), docker/login-action v3→v4, docker/build-push-action v6→v7, and softprops/action-gh-release v1→v3 (v1 was Node 16). Each one's release notes were checked against the inputs these workflows pass: none has a breaking change beyond the runtime, which GitHub-hosted runners already support. FORCE_JAVASCRIPT_ACTIONS_TO_NODE24, which forced the old actions onto Node 24, is removed. One behaviour change to know about: since action-gh-release v2.4.1, a release whose body_path file is missing is published with an empty body instead of failing the job.
  • Linux CI runs on Ubuntu 26.04, on both architectures, and names its version. GitHub's ubuntu-latest label becomes Ubuntu 26 from October 19, 2026. Every workflow now names ubuntu-26.04 (x86_64) and ubuntu-26.04-arm (aarch64) instead of ubuntu-latest, so a future image change is a deliberate edit. The wheels build inside the manylinux container and do not see the host; what moves is the Linux C++ test job, which compiles with the runner's own toolchain: GCC 13 → 15 and CMake 3.31 → 4.4, plus Ubuntu 26's apt versions of GMP, MPFR, Eigen and OpenMPI. Checked beforehand on aarch64 with conda-forge GCC 15.3 and CMake 4.4.3: the core and every C++ test suite build with no errors, and all ten suites pass, threaded and with OMP_NUM_THREADS=1. The wheel artifact is named from the OS, so wheels-ubuntu-latest-3.11 becomes wheels-ubuntu-26.04-3.11, renamed consistently in the job that uploads it and both docs jobs that download it; the Linux C++ ccache starts cold under the new name. (Two commits: a pin to 24.04, then the move to 26.04; reverting the second restores the pin.)
  • A release checks its notes before building anything. The GitHub release publishes CHANGELOG.md's top block, which a one-line extraction used to cut out; it returned an empty string when the separator lines were missing, and nothing checked the block's version or date. tools/release_notes.py does the same extraction and fails when there is no top block, when its heading is not ## [X.Y.Z] - YYYY-MM-DD for the tag's version (typically still unreleased), when it has nothing under the heading, or when it exceeds GitHub's 125,000-character limit for a release description. publish.yml runs it in check_version, the release's first job, so an unready changelog fails a final release in seconds instead of after every wheel has built, and again to write the notes. Prereleases skip it (no GitHub release), and pull requests do not run it. tools/test_release_notes.py covers each failure and checks the extraction matches the old one-liner on the real CHANGELOG. Today the check fails, correctly, because 4.0.0 is still unreleased.
  • The Linux development environment compiles with GCC 15. environment.yml pinned gxx==13.3.0; it is now gxx==15.3.0, matching the GCC 15 that CI's Linux C++ jobs use on Ubuntu 26.04, so code that builds for a developer builds in CI. No workflow uses this file.
  • CLAUDE.md records what the 4.0 preparation settled: CI's Linux C++ jobs compile with GCC 15 (and a compiler change needs a fresh build directory); how the plot refresh works (scripts run in their image folder, plots fail unless every image was written, refresh and doctest records go under python/docs/build, emptied each run); a records session lasts the process (ADR-0066); a wheel is not ABI-coupled to a user's own eigenpy, only source builds against shared libraries are; and developing means a real editable install.
  • The GitLab mirror sync workflow is removed. Mirroring to GitLab is handled outside this repository's workflows now. The workflow ran on every push to every branch and did nothing where the GITLAB_* secrets were unset; nothing else referred to it.

🤖 Generated with Claude Code

ofloveandhate and others added 14 commits September 28, 2026 11:53
GitHub is removing Node 20 from its runners, and the doc-lint and build runs warned about it.  Seven actions targeted an old runtime, and each moves to its lowest major on Node 24: setup-python v5->v6, setup-miniconda v3->v4, upload-artifact v5->v6, download-artifact v5->v7 (v6 is still Node 20), docker/login-action v3->v4, docker/build-push-action v6->v7, and softprops/action-gh-release v1->v3 (v1 was Node 16).  Their release notes list no breaking change beyond the runtime that touches the inputs these workflows pass.  checkout@v5 and cache@v5 were already on Node 24; the rest are composite actions.

FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 forced the old actions onto Node 24 to silence the warning; with none left, it goes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GitHub's ubuntu-latest label becomes Ubuntu 26 from October 19, 2026.  Every workflow now names ubuntu-24.04 instead, matching the aarch64 runner (already ubuntu-24.04-arm), so nothing changes under the 4.0 release: the Linux C++ test job installs GMP, MPFR, Eigen and OpenMPI through apt, and Ubuntu 26 would bring new versions of each.  The move to 26 is planned for 4.1.

The wheel artifact is named from the OS, so wheels-ubuntu-latest-3.11 becomes wheels-ubuntu-24.04-3.11 in the job that uploads it and both docs jobs that download it.  The ccache for the Linux C++ tests is keyed by OS name too, so its first run under the new name is cold.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The GitHub release publishes CHANGELOG.md's top block, which a one-line extraction in the release job cut out: it returned an empty string when the separator lines were missing, so the release went out with an empty description, and nothing checked that the block was for the tag's version or had been dated.

tools/release_notes.py does the same extraction and fails when there is no top block, when its heading is not '## [X.Y.Z] - YYYY-MM-DD' for the tag's version (typically still 'unreleased'), when it has nothing under the heading, or when it is longer than a GitHub release description may be.  publish.yml runs it in check_version, the release's first job, so an unready changelog fails a final release in seconds instead of after every wheel has built, and again in the release job to write the notes.  Prereleases make no GitHub release and skip it; pull requests do not run it, since the version is a release-time decision.  It prints only the notes, not the whole changelog.

tools/test_release_notes.py (run by hand, like the other tools tests) covers each failure and checks that the extraction matches the old one-liner's on the real CHANGELOG.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Mirroring to GitLab is handled outside this repository's workflows now.  The workflow ran on every push, to every branch, and was a no-op wherever the GITLAB_* secrets were not set.  Nothing else referred to it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ubuntu-24.04 becomes ubuntu-26.04 and ubuntu-24.04-arm becomes ubuntu-26.04-arm in every workflow; both images are generally available.  The wheels build inside the manylinux container and do not see the host; what moves is the Linux C++ test job, which compiles with the runner's own toolchain: GCC 13 -> 15 and CMake 3.31 -> 4.4, plus Ubuntu 26's apt versions of GMP, MPFR, Eigen and OpenMPI.

Checked beforehand on aarch64 with conda-forge GCC 15.3 and CMake 4.4.3: the core and every C++ test suite configure and build with no errors and no CMake warnings, and all ten suites pass, threaded and with OMP_NUM_THREADS=1.

Workflows still name the Ubuntu version rather than ubuntu-latest, so a future image change is a deliberate edit.  Artifact names follow the OS (wheels-ubuntu-26.04-3.11 in the upload and both docs downloads), and the Linux C++ ccache starts cold under the new name.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
environment.yml pinned gxx 13.3.0; it is now 15.3.0, matching what CI's Linux C++ jobs compile with since the move to Ubuntu 26.04 (GCC 15), so code that builds for a developer builds in CI.  The core and every C++ test suite were built and run with conda-forge GCC 15.3 before the switch: no errors, all suites passing.  No workflow uses this file; it is for development environments only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- the compiler: CI's Linux C++ jobs compile with GCC 15 on Ubuntu 26.04, environment.yml pins gxx 15.3.0 to match, and a compiler change needs a fresh build directory;
- how the plot refresh works: scripts run in their image folder and save with plain filenames, a plot fails unless every listed image was written, and refresh and doctest records go under python/docs/build, emptied each run so a solve is computed rather than recalled;
- a records session lasts the process and its files close when no solve uses it (ADR-0066);
- a wheel carries private copies of eigenpy and Boost.Python, so it is not ABI-coupled to a user's own eigenpy; only source builds against shared libraries are;
- developing means a real editable install, whose installed version comes from VERSION.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…laceholder

all_solutions() holds an empty vector for a path that went to infinity or failed, and projecting that onto a variable group raised CoordinatesOfGroup: point is shorter than the system's variable structure implies.  The placeholder passes through empty, so the list keeps one entry per path, aligned with solution_metadata().

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The factorization from #401 QR-factors a tall seed matrix, and for a real request that seed was a matrix of units, which for real numbers means signs.  A tall matrix of signs has only 2^thin distinct rows, so the wide real result had at most 2^rows distinct columns: a 3 x 5 real draw had 3, an 8 x 4908 one had 256, and randomizing an overdetermined deflated system down to square with random_matrix(n, m, real=True) produced a singular square system at a point where the deflated Jacobian had full rank.  The real seed is a continuous draw on [-1, 1] now; the QR still launders it into an orthonormal matrix, now a generic one.  Complex draws are unchanged.  Real orthonormal draws differ from before for the same seed.

Found by the cellular decomposition port's deflate-refine oracle tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…aceholder

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ndgame does

At security level 0, two consecutive endpoint approximations whose largest coordinate is above max_norm truncate a path.  The power series endgame asks that after every approximation; the Cauchy endgame tested acceptance first, so a path that converged to a finite point above the ceiling came back Success from Cauchy and SecurityMaxNormReached from power series: for x^2 = 1e8, y = 2x at the default ceiling, two solutions under one endgame and none under the other.

Cauchy now asks security before acceptance, in both of its loops, and never accepts an approximation above the ceiling.  The second part is needed because its count runs over operating-zone rounds only while acceptance needs a single one, so the count could still be at one when the path was accepted.  The zone condition stays: an out-of-zone Cauchy mean is not an endpoint approximation.

Tests pin the rule over both trackers and both endgames, in C++ and Python.  They lower the ceiling instead of raising the roots, because the double precision tracker runs out of steps before the endgame on a badly scaled system (always for x^2 = 1e6, in some draws for x^2 = 1e4).  The SecurityConfig.level docstring said the opposite of what the level does.  ADR-0067.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The archive change was mentioned only inside the entry about a System no longer carrying a precision. It is now stated with the other compatibility breaks at the top of the 4.0 block, and it says that pickles are affected, since a pickle holds an archive. Checked against v3.4.0: the precision member left the archive and the auxiliary variable groups and auxiliary coordinates joined it, while the list of registered node classes is the same in both.

Found by the cellular decomposition port, whose pickled test fixture could not be read under 4.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@ofloveandhate ofloveandhate left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is some math in this one -- namely, that cauchy can now truncate in the same way as PSEG, for security-level truncation. i experienced the difference in the work i am doing on the cellular decomposition algoirthm using b2, and so wanted the same behaviour regardless of the endgame i am using.

there are additionally CI improvements that I hope will make relasing smoother, and let me not have to change runner setup for a while.

@ofloveandhate
ofloveandhate merged commit e638995 into develop Oct 3, 2026
54 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant