- doc/release-policy.md:85 corrected `doc/api/tests.md` link to relative `api/tests.md` (was resolving to nonexistent doc/doc/api/tests.md). - doc/tutorials/block-fd-hessian.md:40 redirected stale reference `../math/hyper-ideal.md` to the actual file `../math/geometry-modes.md`. Found by a sweep of all doc/*.md before the reviewer meeting. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
217 lines
9.4 KiB
Markdown
217 lines
9.4 KiB
Markdown
# Release & versioning policy
|
|
|
|
> **Audience:** maintainers and recurring contributors of conformallab++.
|
|
> External users only need this if they are publishing a fork.
|
|
>
|
|
> **Created:** 2026-05-22, after the v0.9.0 release that exposed two
|
|
> recurring failure modes: (a) the v0.9.0 tag had to be moved twice
|
|
> because release-prep landed on the wrong commit, and (b) the test
|
|
> counts were hardcoded in eight different documents and drifted apart.
|
|
|
|
This document codifies how conformallab++ chooses version numbers,
|
|
how releases are produced, and which artefacts must stay in sync.
|
|
|
|
---
|
|
|
|
## 1. Version-number rules (SemVer)
|
|
|
|
The project follows [Semantic Versioning 2.0](https://semver.org).
|
|
Tag format: `vMAJOR.MINOR.PATCH` (e.g. `v0.9.0`).
|
|
|
|
### Pre-1.0 phase (current — until CGAL submission)
|
|
|
|
While the project is at version `0.x.y`, the public API is **not yet
|
|
frozen**. The convention we use during the pre-1.0 phase is:
|
|
|
|
| Bump | When |
|
|
|---|---|
|
|
| **`0.x.0 → 0.(x+1).0`** (MINOR) | Significant new feature: new functional, new Newton solver, new public CGAL entry, new Phase milestone completed. May break the public API. Treated as the "interesting" release type during pre-1.0. |
|
|
| **`0.x.y → 0.x.(y+1)`** (PATCH) | Bug fixes, performance optimisations without API change, doc-only follow-up releases, CI/infrastructure fixes. Never breaks the public API. |
|
|
| **`0.x.y → 1.0.0`** | API freeze + CGAL submission readiness. All public headers under `include/CGAL/` are stable. Cumulative changelog updated to call out every public-API decision in retrospect. |
|
|
|
|
Phase milestone → MINOR-bump mapping (historical + planned):
|
|
|
|
| Tag | Phase milestone |
|
|
|-----------|--------------------------------------------------------|
|
|
| `v0.1.0` | Phase 1 (special functions) |
|
|
| `v0.2.0` | Phase 2 (hyper-ideal geometry) |
|
|
| `v0.7.0` | Phase 7 complete (period matrix, fundamental domain) |
|
|
| `v0.9.0` | Phase 9a + 9b + 8b-Lite |
|
|
| `v0.10.0` | Phase 9c (4g-polygon, genus g > 1) |
|
|
| `v0.11.0` | Phase 10a (harmonic + holomorphic 1-forms) |
|
|
| `v1.0.0` | CGAL package submission-ready |
|
|
|
|
### Post-1.0 phase (planned, ≥ `v1.0.0`)
|
|
|
|
Standard SemVer with no pre-1.0 exceptions:
|
|
|
|
| Bump | When |
|
|
|---|---|
|
|
| **MAJOR** (`X.0.0 → (X+1).0.0`) | Any breaking change to the public API: removed function, signature change, renamed CGAL entry, behaviour change of a documented contract. |
|
|
| **MINOR** (`X.Y.0 → X.(Y+1).0`) | New features, new public entries, new Default-traits classes. Strictly additive — no removal, no behaviour change. |
|
|
| **PATCH** (`X.Y.Z → X.Y.(Z+1)`) | Bug fixes only. No new files, no new public symbols. |
|
|
|
|
### Pre-release tags
|
|
|
|
For testing-quality releases:
|
|
|
|
* `v1.0.0-alpha.1`, `v1.0.0-alpha.2`, … — early preview, API may still
|
|
shift.
|
|
* `v1.0.0-beta.1` — feature-complete preview, API stable but tests
|
|
may still find issues.
|
|
* `v1.0.0-rc.1`, `v1.0.0-rc.2`, … — release candidate, only blocker
|
|
fixes before the final tag.
|
|
|
|
### What does NOT trigger a release
|
|
|
|
* Internal refactoring without user-visible change.
|
|
* Documentation-only updates (unless the documentation is itself a
|
|
product, like a new tutorial).
|
|
* Test additions / coverage improvements.
|
|
* CI / infrastructure changes.
|
|
|
|
Group such changes into the next planned release.
|
|
|
|
---
|
|
|
|
## 2. Single source of truth for moving numbers
|
|
|
|
Three numbers tend to drift across multiple documents in any project:
|
|
test counts, version strings, and date strings. The conformallab++
|
|
rule is:
|
|
|
|
| Number / string | Single source of truth | Anywhere else |
|
|
|-----------------------------|--------------------------------|--------------------------------------|
|
|
| **Total / per-suite test counts** | `doc/api/tests.md` | Use qualitative phrasing + link, e.g. "full test suite passes, 0 skipped — see [`doc/api/tests.md`](api/tests.md)". |
|
|
| **Project version** | `CITATION.cff` `version:` field | Don't hardcode in headers, READMEs, doc bodies. Reference by name ("v0.9.0") only when the historical version actually matters (changelog entries, release-note bodies, Phase-milestone tables). |
|
|
| **Release date** | `CITATION.cff` `date-released:` + `CHANGELOG.md` section header | Don't hardcode elsewhere. |
|
|
| **Test-suite description per file** | `doc/api/tests.md` | Headers and code files may list the suites they implement, but never claim a count of suites elsewhere. |
|
|
|
|
### Why qualitative phrasing for test counts
|
|
|
|
The counts change with every PR that adds or removes a test. Hardcoding
|
|
the number "227" in eight documents means eight separate edits per PR —
|
|
and historically we have failed to keep them in sync more than once.
|
|
|
|
The cost of looking up the exact number in `doc/api/tests.md` is one
|
|
click; the cost of fixing a stale "227" in seven places is real PR
|
|
overhead. We pay the click.
|
|
|
|
### Audit script
|
|
|
|
`scripts/check-test-counts.sh` (when present) reads the totals from
|
|
`doc/api/tests.md`, runs `ctest`, and fails the CI if they diverge.
|
|
This catches the `tests.md` itself going stale even if no other doc
|
|
hardcodes the number.
|
|
|
|
---
|
|
|
|
## 3. Release process (checklist)
|
|
|
|
The recipe that worked for v0.9.0 (after the false-start with PR #11 /
|
|
#12). Apply for every `vX.Y.Z` release.
|
|
|
|
### Pre-release prep — on a release branch
|
|
|
|
1. **Update `CHANGELOG.md`** — add a new top-level section
|
|
`## [vX.Y.Z] — YYYY-MM-DD`. Categorise changes by `Added`,
|
|
`Changed`, `Removed`, `Fixed`, `Deprecated`, `Security`. See
|
|
[Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/).
|
|
2. **Update `CITATION.cff`** — `version:` and `date-released:` fields.
|
|
3. **Refresh `doc/api/tests.md`** — re-run the full test suite locally
|
|
and update the per-suite tables + the two `**Total: N tests, 0 skipped.**`
|
|
lines (one for `conformallab_tests`, one for `conformallab_cgal_tests`).
|
|
4. **Run `scripts/check-test-counts.sh`** if present — must pass.
|
|
5. **Verify no hardcoded counts remain** elsewhere:
|
|
```bash
|
|
grep -rn "[0-9]\+ tests pass\|[0-9]\+ tests, 0 skipped\|[0-9]\+ CGAL tests" \
|
|
README.md CLAUDE.md doc/ scripts/ \
|
|
| grep -v "doc/api/tests.md"
|
|
# Expected: zero results (other than tests.md itself).
|
|
```
|
|
6. **Commit** with the message
|
|
`release: vX.Y.Z — <one-line summary>`. Push to a feature branch.
|
|
|
|
### Open the release PR
|
|
|
|
7. **Open one PR** with all prep commits. Title:
|
|
`release: vX.Y.Z (<summary>)`. Description: copy the new
|
|
`CHANGELOG.md` section.
|
|
8. **Wait for CI green** — `test-fast` + `test-cgal` + `doc-build`.
|
|
9. **Merge** with a merge commit (the merge SHA becomes the release
|
|
target).
|
|
|
|
### After-merge — tag and announce
|
|
|
|
10. **Verify `main` head is the merge commit**:
|
|
```bash
|
|
git fetch origin && git log origin/main --oneline -1
|
|
```
|
|
11. **Create the Gitea release** via API or web UI. `target_commitish`
|
|
MUST be the merge SHA from step 10 (NOT the feature branch HEAD).
|
|
The web UI does this automatically; the API needs explicit `sha`.
|
|
12. **Sync the codeberg mirror**:
|
|
```bash
|
|
git fetch origin --tags
|
|
git push codeberg main --tags
|
|
```
|
|
13. **Update CLAUDE.md "Release state" section** so future
|
|
contributors see the new version at a glance. (This is the only
|
|
place where the current version appears outside `CITATION.cff` and
|
|
`CHANGELOG.md`.)
|
|
|
|
### Common failure modes and how to recover
|
|
|
|
| Symptom | Recovery |
|
|
|---|---|
|
|
| Tag points to an earlier commit than the one you wanted | Delete the release + tag via Gitea API, re-create with the correct `target_commitish`. |
|
|
| Release-prep commit lands on a feature branch but not on `main` after merge | Open a fast-follow `release/vX.Y.Z-finalise` PR. Cherry-pick the missing commit; merge; move the tag. |
|
|
| `doc/api/tests.md` counts are stale post-merge | One-line PR: re-run `ctest`, update tests.md, no version bump (it's a doc fix between releases). |
|
|
|
|
---
|
|
|
|
## 4. Hotfix policy
|
|
|
|
For a `vX.Y.0` minor release that needs an urgent fix before the next
|
|
planned minor:
|
|
|
|
1. Branch off the release tag (NOT off `main`):
|
|
```bash
|
|
git checkout -b hotfix/vX.Y.1 vX.Y.0
|
|
```
|
|
2. Apply the minimal fix.
|
|
3. Tag `vX.Y.1` from the hotfix branch.
|
|
4. Merge the hotfix back into `main` so the fix isn't lost.
|
|
|
|
Hotfixes are rare for a research-quality library; the typical path is
|
|
to wait for the next minor. Use hotfixes only for security issues or
|
|
build-broken-on-supported-platform regressions.
|
|
|
|
---
|
|
|
|
## 5. Deprecation policy (post-1.0)
|
|
|
|
When a public symbol is to be removed in version `M.0.0`:
|
|
|
|
1. In any earlier `M-1` minor release, mark it `[[deprecated]]` (C++17)
|
|
or via a Doxygen `\deprecated` tag.
|
|
2. Add a `Deprecated` section to that version's CHANGELOG entry with
|
|
the planned removal version.
|
|
3. Keep the symbol working for at least one full minor cycle before
|
|
removal.
|
|
4. Remove in the `M.0.0` release; document the removal in the
|
|
`Removed` section.
|
|
|
|
Pre-1.0, this policy does not apply — breaking changes are allowed
|
|
on any minor bump as long as they are listed in CHANGELOG.
|
|
|
|
---
|
|
|
|
## 6. Related documents
|
|
|
|
* `CHANGELOG.md` — per-version history.
|
|
* `CITATION.cff` — authoritative version + date for citation.
|
|
* `doc/api/tests.md` — single source of truth for test counts.
|
|
* `doc/contributing.md` — code style + PR mechanics.
|
|
* `doc/roadmap/phases.md` — what each future MINOR bump will deliver.
|