Releasing FaST-LMM
August 8, 2026 ยท View on GitHub
This is the standing release process for FaST-LMM. Short-term release plans and
compatibility investigations belong in specs/; keep this file limited to the
process that should apply to every release.
The maintainer chooses the version and explicitly approves publication. A
release must be built from a clean commit on the repository's default branch,
and its vX.Y.Z tag must point to that exact commit.
Release order
Publish and verify any required PySnpTools and fastlmmclib releases before
final FaST-LMM qualification. Update FaST-LMM's minimum dependency versions to
the first compatible published releases.
Final qualification must install those prerequisites from PyPI, not from sibling source checkouts, Git dependencies, or prereleases.
One-time repository setup
- Configure a PyPI Trusted Publisher for the
fastlmm/FaST-LMMrepository,.github/workflows/release.yml, and a protected GitHubpypienvironment. - Require maintainer approval for the
pypienvironment and restrict it to version tags. - Give the publish job only the permissions it needs, including
id-token: write. Other jobs need onlycontents: read. - Pin third-party GitHub Actions to reviewed full commit SHAs and pin
uvto a reviewed version. - Pass the distributions built and tested by CI to the publish job as an artifact. Never rebuild them in the publish job.
The release workflow must publish with PyPI Trusted Publishing and retain the generated attestations. Do not store PyPI passwords or API tokens in the repository or GitHub Actions.
Prepare the release
-
Start from a clean release branch based on the current default branch.
-
Review open issues, pull requests, and dependency advisories for anything that affects the release.
-
Set the version in
pyproject.tomland update the release notes with the release date, compatibility changes, deprecations, and user-visible fixes. -
Confirm that the required published PySnpTools and
fastlmmclibversions install on every supported Python version and platform. -
Confirm that dependency bounds and Python-version markers describe versions actually tested in CI. Exercise the declared direct minimums on the oldest and newest supported Python versions:
uv venv --python 3.10 .minimum-310 uv pip install --python .minimum-310/bin/python --resolution lowest-direct --editable ".[bgen]" cd tests ../.minimum-310/bin/python test.py cd .. uv venv --python 3.14 .minimum-314 uv pip install --python .minimum-314/bin/python --resolution lowest-direct --editable ".[bgen]" cd tests ../.minimum-314/bin/python test.py cd .. -
Regenerate and commit
uv.lock, then verify it:uv lock --check -
Run the complete canonical test suite and all supported optional-dependency suites from the locked environment:
uv sync --frozen --all-extras cd tests uv run --frozen --no-sync python test.py cd .. -
Run representative end-to-end association and inference tests. Investigate every change in numerical results, tolerances, ordering, dtypes, or result schemas before updating expected output.
-
Execute the maintained notebooks from start to finish in clean environments and inspect their results. Build the documentation from its sources and check links and examples. Create the locked Python 3.14 notebook environment with:
UV_PROJECT_ENVIRONMENT=.venv-notebook314 uv sync --python 3.14 --frozen --all-extras --group notebook fastlmm_docs_output="$(mktemp -d)" UV_PROJECT_ENVIRONMENT=.venv-notebook314 uv run --frozen --no-sync sphinx-build -W --keep-going -E -a -d /tmp/fastlmm-doctrees -b html doc/source "$fastlmm_docs_output" diff -ru --exclude=.nojekyll "$fastlmm_docs_output" docs UV_PROJECT_ENVIRONMENT=.venv-notebook314 uv run --frozen --no-sync sphinx-build -W --keep-going -E -a -b linkcheck doc/source doc/build/linkcheckThe maintained public notebooks are the four linked from
README.md. Record any deliberately skipped machine-specific or multi-hour example and why it was not part of the routine execution pass. -
Build the source distribution and wheel without local source overrides:
uv build --no-sources -
Inspect both artifact manifests for required metadata, licenses, sample data, hashdown files, native executables, and package data. Confirm that development files, caches, notebooks, and generated output are absent unless intentionally distributed.
-
Install and test the exact wheel and source distribution in clean environments on the oldest and newest supported Python versions, outside the source checkout and without the repository on
PYTHONPATH. -
Verify the installed
fastlmmclibnative artifact on every supported operating-system and architecture combination. -
Wait for all required CI jobs to pass on every supported operating system and Python version. Resolve warnings that indicate a compatibility, packaging, numerical, or security problem.
If the repository does not yet have the locked uv workflow assumed above,
finish that migration before releasing rather than substituting an unreviewed
release path.
Publish
-
Merge the reviewed release change into the default branch and confirm that it is clean and up to date.
-
Confirm that the version is not already present on PyPI and that the tag does not already exist.
-
Create and push an annotated tag at the release commit:
git tag -a vX.Y.Z -m "FaST-LMM X.Y.Z" git push origin vX.Y.Z -
Verify that the tag workflow builds and tests the exact artifacts intended for publication.
-
Review the workflow summary and approve its protected
pypienvironment. -
Confirm that PyPI received both the wheel and source distribution and that their attestations are present.
-
Create the matching GitHub release from the release notes.
Verify the published release
- Install
fastlmm==X.Y.Zand its dependencies from PyPI into a fresh environment with no sibling checkout onPYTHONPATH. - Run representative association and inference smoke tests against the published artifacts on the oldest and newest supported Python versions.
- Run the relevant InstallTest scenarios.
- Build or deploy the website from its source repository and verify the rendered documentation, examples, downloads, and tutorial links.
- Close or update the issues and pull requests resolved by the release, linking to the published version or its CI evidence.
Failed releases
Do not move or replace a published version tag, and do not upload different files under an existing version. If a published release is unusable, yank it on PyPI with a concise reason and publish a corrected version. Preserve the failed release's tag and evidence for traceability.
TestPyPI may be used through a separate Trusted Publisher when a publishing workflow itself needs qualification. It does not replace clean local artifact tests or final testing against the real PyPI dependency ecosystem.