Development and validation

中文 · Contributing

Reference environment

Python 3.10+ and uv; the runtime uses only the standard library. From the repository root:

uv sync --locked --python 3.10
uv run --locked python -m unittest discover -s tests -v
uv run --locked python examples/single_scale.py
uv run --locked python examples/filtration.py
uv run --locked ruff check .
uv run --locked ruff format --check .
uv build --no-build-isolation
pwsh -NoProfile -File ./scripts/check_docs.ps1
git diff --check

Missing native dependencies explicitly skip native tests. A reference pass does not validate native code. uv build creates local artifacts; public uploading follows the release procedure below. There is no independent typecheck command.

Native and oracle checks

Build/install the matching wheel using the native guide.

$env:HOMOLOGY_NATIVE_REQUIRED = '1'
uv run --locked --no-sync python -m unittest discover -s tests -v
cargo +1.98.1 fmt --manifest-path native/Cargo.toml --check
cargo +1.98.1 clippy --manifest-path native/Cargo.toml --locked --all-targets -- -D warnings
$env:PYO3_PYTHON = Join-Path (Get-Location) '.venv/Scripts/python.exe'
cargo +1.98.1 test --manifest-path native/Cargo.toml --locked --lib

Use .venv/bin/python on Linux. Rebuild after Rust changes; --no-sync retains the extension. The optional GUDHI test environment is locked independently:

uv sync --locked --group oracle --group oracle-secondary --python 3.12
$env:HOMOLOGY_GUDHI_REQUIRED = '1'
uv run --locked --group oracle --group oracle-secondary python -m unittest discover -s tests -p test_simplicial_inputs.py -v
uv run --locked --group oracle --group oracle-secondary python -m unittest discover -s tests -p test_gudhi_oracle.py -v
uv run --locked --group oracle --group oracle-secondary python -m unittest discover -s tests -p test_oracle_corpus.py -v

These tests compare actual simplicial inputs and F2 stage Betti/barcode/rank results. The 77-input regression also checks same-P geometry and snapshot restoration. Oracles never populate production results. See fixture provenance.

Documentation and GitHub Pages

Sphinx + MyST + Furo requires Python 3.11+; CI uses 3.12.

uv venv .task-artifacts/docs-env --python 3.12
uv pip install --python .task-artifacts/docs-env/Scripts/python.exe -r docs/requirements.txt
.task-artifacts/docs-env/Scripts/python.exe -m sphinx -E -n -W --keep-going -b html docs .task-artifacts/docs-site
.task-artifacts/docs-env/Scripts/python.exe -m sphinx -E -n -W --keep-going -b html docs/en .task-artifacts/docs-site/en

On Linux use bin/python. Run the PowerShell 7 Markdown checker and execute changed code snippets separately. The checker rejects inconsistent table widths and unprotected math delimiters. Use GitHub backtick-protected inline math and math fences; shared Sphinx configuration converts them to MyST math nodes at build time. The checker rejects GitHub’s forbidden \operatorname; use \mathrm{...} for upright names. It does not fully validate TeX syntax, remote availability, or heading anchors. After editing formulas, also check GitHub’s client rendering. Successful main builds deploy both languages to GitHub Pages; pull requests only build.

Change-specific validation and CI

Validate input shapes/AD=0/positive weights; all four projection conditions; same-P geometry and arithmetic; transport composition/rank/oracle agreement; certificate replay; identity mixing/tampering; JSON and legacy round trips. Native changes require independent reference/enumeration checks and word boundaries.

Reference CI checks Linux Python 3.10/3.12 and isolated reference wheels. Native CI checks Windows Python 3.10 and Linux Python 3.12 with required native tests and isolated dual wheels. Oracle CI forces GUDHI comparisons. Documentation CI builds both languages strictly and deploys main. Local and remote results belong to their exact source identities. Temporary outputs and wheels stay in ignored directories.

Public releases

The homology-operator distribution provides an OS-independent wheel and source archive. Version 0.0.2 has a standard-library-only runtime. The optional Rust package is built separately from matching source and is not uploaded to PyPI. During 0.x, patch releases preserve the public API; breaking changes require a minor-version increase and release notes. Regression tests cover existing schema 1/2 restoration and preserve historical fixture versions/hashes.

Before release, synchronize pyproject.toml, __version__, uv.lock, CITATION.cff, and the documentation version. Run the checks above, including strict builds of both documentation languages, and verify all main CI for the release commit. New result provenance reports the installed package version.

Register a pending publisher on PyPI with project homology-operator, owner proffitteoy, repository homology-operator, workflow release.yml, and environment pypi. The release workflow runs on a published GitHub Release whose tag is v plus the package version, such as v0.0.2. It tests Python 3.10/3.12, builds/checks wheel and sdist metadata, and runs the full applicable suite against the isolated wheel before uploading those same artifacts. The publishing job uses the pypi environment and short-lived OIDC identity.

uv build --no-build-isolation
uv tool run --from twine==6.2.0 twine check --strict dist/*
gh release create v0.0.2 --target <verified-commit-sha> --title "homology-operator 0.0.2" --notes-file <release-notes-file>

Verify the workflow, PyPI version record, uploaded SHA-256 digests, and a fresh installation from PyPI. A GitHub Release or successful build alone does not prove that PyPI uploading completed.