Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
3.12/3.13/3.14, drop 3.10/3.11 in a dedicated support-policy release). It is a
decision record only — `pyproject.toml`, the CI matrix, and classifiers are
unchanged in this PR.
- Consolidated the duplicate support-policy ADR: the governance detail from
`docs/ADR_SUPPORT_POLICY.md` (release classification, evidence gate, the
required-steps checklist) is merged into `docs/adr/0001-python-support-policy.md`,
and the old path is reduced to a pointer stub so existing links still resolve.
Single numbered ADR going forward.

### CI
- `pypi.yml`: the Trusted-Publishing step now sets `print-hash: true` so each
Expand Down
93 changes: 7 additions & 86 deletions docs/ADR_SUPPORT_POLICY.md
Original file line number Diff line number Diff line change
@@ -1,89 +1,10 @@
# ADR: Support policy after v0.5.0
# ADR: Support policy after v0.5.0 — moved

Date: 2026-06-27
Status: Accepted for policy; runtime-baseline change deferred
Scope: LiouScope packaging, CI matrix, dependency floors, release governance
This decision record has been consolidated into the numbered ADR directory and
now lives at:

## Context
- **`docs/adr/0001-python-support-policy.md`** — Scientific-Python support policy
(SPEC 0).

LiouScope is a scientific Python package with a deliberately broad v0.5.0 runtime
matrix (`python_requires >=3.10`; CI on Python 3.10, 3.11, 3.12, 3.13, 3.14).
Issue #59 asks for an explicit support policy rather than silently changing the
runtime baseline inside an unrelated hardening PR.

The relevant external policy anchor is SPEC 0, which recommends dropping support
for older Python feature releases three years after initial release and core
package dependencies two years after initial release. SPEC 0 is a Scientific
Python ecosystem recommendation, not a claim that upstream Python itself is EOL.

## Decision

1. **Do not drop Python 3.10 or 3.11 in v0.5.x.** The v0.5.0 public-release lane
remains focused on archiving, publication, citation metadata, and evidence
locking. Keeping the existing runtime matrix avoids mixing user-visible
support changes into a release-publication gate.
2. **Adopt SPEC 0 as the forward support-policy reference.** Future baseline PRs
must compare Python and core dependency floors against SPEC 0 and document any
intentional deviation.
3. **First candidate post-v0.5 baseline:** Python 3.12+ with CI on 3.12, 3.13,
and 3.14. This is a candidate, not an automatic change. It requires a dedicated
PR and release note.
4. **No silent dependency-floor bumps.** Raising NumPy/SciPy floors must be done
together with CI evidence, resolver checks, and a compatibility note. A floor
may remain older than SPEC 0 temporarily if needed for user compatibility, but
the deviation must be explicit.
5. **Mypy target is not the runtime floor.** The current `mypy` target of Python
3.12 is a toolchain workaround for modern NumPy stubs. It does not imply that
Python 3.10/3.11 runtime support has been removed while those interpreters stay
in the CI test matrix.

## Required steps for a future Python 3.12+ baseline PR

A future PR that actually drops Python 3.10/3.11 must update all of the following
in one coherent change:

- `pyproject.toml`:
- `requires-python = ">=3.12"`
- remove Python 3.10 and 3.11 Trove classifiers
- `.github/workflows/ci.yml`:
- remove Python 3.10 and 3.11 matrix legs
- keep at least 3.12, 3.13, and 3.14 while they are active supported baselines
- `.github/workflows/ci-reusable-pilot.yml`:
- update the generated pilot matrix consistently
- keep the matrix validation fail-closed
- Documentation:
- changelog entry under `[Unreleased]`
- release audit / release notes support-policy paragraph
- README compatibility badge or installation note if one exists at that point

## Release classification

Dropping interpreter support is user-visible. It must not be hidden in a patch
release. For LiouScope governance, the default classification is:

- PATCH: bug fixes and fail-closed hardening that keep the same supported runtime
floor.
- MINOR: additive APIs, new diagnostics, and explicitly announced baseline-policy
updates when no public stable API is broken.
- MAJOR: reserved for breaking public API, manifest, or diagnostic-report contract
changes. If downstream users rely materially on Python 3.10/3.11, the project
may choose a MAJOR bump for the interpreter drop even if the Python packaging
ecosystem often handles such drops in MINOR releases.

## Evidence gate

Before a baseline PR is marked ready, it must include:

- CI green on every retained Python version.
- `ruff`, `mypy`, anchor regressions, full suite, and QuTiP cross-checks green.
- A dependency resolver smoke test from a clean environment.
- A changelog note that distinguishes SPEC-0 recommendation from upstream Python
EOL status.

## Non-goals

- No D24 claim expansion.
- No manifest schema bump.
- No change to v0.5.0 archive/citation gates.
- No claim that Python 3.10 or 3.11 is upstream-EOL merely because it is outside
the SPEC-0 recommended Scientific Python support window.
This stub is retained only so existing links do not break. See
`docs/adr/README.md` for the ADR index and conventions.
146 changes: 113 additions & 33 deletions docs/adr/0001-python-support-policy.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
# ADR 0001 — Scientific-Python support policy (SPEC 0)

- **Status:** Accepted
- **Date:** 2026-06-26
- **Date:** 2026-06-26 (consolidated 2026-06-29)
- **Deciders:** LiouScope maintainers
- **Supersedes:** —
- **Supersedes:** `docs/ADR_SUPPORT_POLICY.md` (folded in here; that path is now a
pointer stub)
- **Superseded by:** —

> This ADR consolidates two parallel records of the same decision: the original
> `docs/adr/0001-…` (PR #64) and `docs/ADR_SUPPORT_POLICY.md` (PR #61). The
> governance detail from the latter (required-steps checklist, release
> classification, evidence gate) is merged in below; the numbered `docs/adr/`
> structure and the web-verified SPEC 0 dates are kept.
Comment thread
marcohost33-maker marked this conversation as resolved.

## Context

LiouScope currently declares `requires-python = ">=3.10"` and runs its CI test
matrix on Python 3.10 / 3.11 / 3.12 / 3.13 / 3.14, with Trove classifiers to
match. As the project moves past `v0.5.0`, two pressures push toward narrowing
the supported runtime window:
LiouScope is a scientific Python package with a deliberately broad v0.5.0 runtime
matrix (`requires-python >=3.10`; CI on Python 3.10, 3.11, 3.12, 3.13, 3.14).
Issue #59 asks for an explicit support policy rather than silently changing the
runtime baseline inside an unrelated hardening PR.

Two pressures push toward narrowing the supported runtime window:

1. **Toolchain drift.** NumPy ≥ 2.5 ships type stubs that use the PEP 695 `type`
statement; mypy only accepts them when its `python_version` target is ≥ 3.12,
Expand All @@ -22,36 +31,96 @@ the supported runtime window:
dependency-floor compatibility surface, and the set of behaviours the anchor
regressions must hold invariant.

The [Scientific Python ecosystem][spec0] addresses exactly this with
**SPEC 0 — Minimum Supported Dependencies**, which recommends:
The relevant external anchor is [Scientific Python SPEC 0][spec0], which
recommends:

- support each **Python** minor for **3 years** after its initial release, and
- support each **core package** (NumPy, SciPy, …) for **2 years** after its
release.

SPEC 0 is a Scientific-Python *ecosystem* recommendation, **not** a claim that
upstream Python itself is EOL.

Under SPEC 0's published drop schedule (verified 2026-06-29): Python 3.10
(released 2021-10-04) and 3.11 (released 2022-10-24, SPEC 0 support window ending
**2025-10-23**) are already past the recommended 3-year window, while Python 3.12
(released 2023-10-02) remains inside it until **2026-10-01**.

## Decision

LiouScope adopts **SPEC 0** as the reference policy for its Python and core
dependency support windows.

**Post-`v0.5.0` target (to be enacted in a dedicated support-policy release, not
as a side-effect of an unrelated change):**

- `requires-python = ">=3.12"`
- CI test matrix: **3.12 / 3.13 / 3.14**
- Drop the 3.10 and 3.11 legs, their Trove classifiers, and any 3.10/3.11-only
compatibility shims **together** in that one release.
- Re-evaluate NumPy/SciPy floors against the SPEC 0 2-year window at the same
time (separately reviewed; not mandated by this ADR).

Until that release ships, the **status quo is unchanged**: `>=3.10` and the
five-version matrix remain in force. This ADR records the decision and its
rationale; it does **not** modify `pyproject.toml`, the CI matrix, or classifiers.
1. **Do not drop Python 3.10 or 3.11 in v0.5.x.** The v0.5.0 public-release lane
stays focused on archiving, publication, citation metadata, and evidence
locking; user-visible support changes must not be mixed into a
release-publication gate.
2. **Adopt SPEC 0 as the forward support-policy reference.** Future baseline PRs
must compare Python and core-dependency floors against SPEC 0 and document any
intentional deviation.
3. **First candidate post-v0.5 baseline:** `requires-python >=3.12` with CI on
3.12, 3.13, and 3.14. This is a *candidate*, not an automatic change; it
requires a dedicated PR and release note.
4. **No silent dependency-floor bumps.** Raising NumPy/SciPy floors must be done
together with CI evidence, resolver checks, and a compatibility note. A floor
may remain older than SPEC 0 temporarily for user compatibility, but the
deviation must be explicit.
5. **Mypy target is not the runtime floor.** The current `mypy` target of Python
3.12 is a toolchain workaround for modern NumPy stubs. It does **not** imply
that Python 3.10/3.11 runtime support has been removed while those interpreters
remain in the CI test matrix.

This ADR is a **decision record only** — it does not modify `pyproject.toml`, the
CI matrix, or the Trove classifiers.

## Required steps for a future Python 3.12+ baseline PR

A future PR that actually drops Python 3.10/3.11 must update all of the following
in one coherent change:

- `pyproject.toml`:
- `requires-python = ">=3.12"`
- remove the Python 3.10 and 3.11 Trove classifiers
- `.github/workflows/ci.yml`:
- remove the Python 3.10 and 3.11 matrix legs
- keep at least 3.12, 3.13, and 3.14 while they are active supported baselines
- `.github/workflows/ci-qutip.yml`:
- trim the `qutip-cross-check` matrix (currently `["3.11", "3.12"]`) to drop the
3.11 leg. This workflow registers its own *required* status checks
independently of `ci.yml`, so a stale 3.11 leg here would keep an
"unsupported" interpreter in CI even after `ci.yml` is updated.
- `.github/workflows/ci-reusable-pilot.yml`:
- update the generated pilot matrix consistently
Comment thread
marcohost33-maker marked this conversation as resolved.
- keep the matrix validation fail-closed
- Branch protection:
- update the required-status-check list (`gh api`) so the removed
`test (… 3.11)` / `qutip-cross-check (3.11)` checks are no longer required;
otherwise the protected branch waits forever on checks that never run again.
- Documentation:
- changelog entry under `[Unreleased]`
- release-audit / release-notes support-policy paragraph
- README compatibility/installation note if one exists at that point

## Release classification

Dropping interpreter support is user-visible and must not be hidden in a patch
release. Default LiouScope governance classification:

- **PATCH:** bug fixes and fail-closed hardening that keep the same supported
runtime floor.
- **MINOR:** additive APIs, new diagnostics, and explicitly announced
baseline-policy updates when no public stable API is broken.
- **MAJOR:** reserved for breaking public API, manifest, or diagnostic-report
contract changes. If downstream users rely materially on Python 3.10/3.11, the
project may choose a MAJOR bump for the interpreter drop even though the Python
packaging ecosystem often handles such drops in MINOR releases.

## Evidence gate

Before a baseline PR is marked ready, it must include:

- CI green on every retained Python version.
- `ruff`, `mypy`, anchor regressions, full suite, and QuTiP cross-checks green.
- A dependency-resolver smoke test from a clean environment.
- A changelog note that distinguishes the SPEC-0 recommendation from upstream
Python EOL status.

## Consequences

Expand All @@ -65,25 +134,36 @@ rationale; it does **not** modify `pyproject.toml`, the CI matrix, or classifier

- Dropping supported runtimes is **SemVer- and governance-relevant**: it changes
`requires-python`, the CI matrix, classifiers, dependency floors, and release
notes. It must therefore land in its **own** PR with a `CHANGELOG.md` migration
note, not be folded into a feature or fix PR.
notes. It must land in its **own** PR with a `CHANGELOG.md` migration note.
- Anchor regressions (`tests/test_anchors.py`) must stay green across the new,
narrower matrix; the drop PR re-verifies them as the sacred gate.

## Non-goals

- This ADR is **not** a claim that the upstream CPython project considers 3.10 or
3.11 unsupported. SPEC 0 is a *Scientific-Python ecosystem* support-window
convention; those interpreters continue to receive upstream security fixes on
their own schedule.
- It does not bump any dependency floor by itself, and it does not change the
`ruff` `target-version` (tracked separately in the enacting release).
- **Not** a claim that the upstream CPython project considers 3.10 or 3.11
unsupportedSPEC 0 is an ecosystem support-window convention.
- No dependency-floor bump by itself, and no change to the `ruff`
`target-version` (tracked in the enacting release).
- No D24 claim expansion, no manifest-schema bump, no change to the v0.5.0
archive/citation gates.

## References

- SPEC 0 — Minimum Supported Dependencies: <https://scientific-python.org/specs/spec-0000/>
- `CHANGELOG.md` — v0.5.0 "Fixed": mypy `python_version` raised to 3.12.
- `AGENTS.md` §"Working agreements" — branch-protection / required-check policy.
- Roadmap issue #59 (post-v0.5 architecture & policy items).
- Roadmap issue #59 (post-v0.5 architecture & policy items); PRs #61, #64.

## Revision history

The **decision** in this ADR is unchanged across the entries below; only the
record's location and surrounding detail were edited (an *editorial
consolidation*, not a decision change — see `docs/adr/README.md` for the
immutability convention that distinguishes the two).

| Date | Change | PR |
|------|--------|----|
| 2026-06-26 | Accepted. Original record created at `docs/adr/0001-python-support-policy.md`. | #64 |
| 2026-06-29 | Editorial consolidation. Merged the governance detail (release classification, evidence gate, required-steps checklist) from the parallel `docs/ADR_SUPPORT_POLICY.md` (PR #61) into this record; reduced that path to a pointer stub. No decision change. | #66 |

[spec0]: https://scientific-python.org/specs/spec-0000/
11 changes: 8 additions & 3 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ This directory holds LiouScope's Architecture Decision Records — short,
append-only documents that capture a significant decision, its context, and its
consequences. The format is a lightweight [MADR][madr]-style template.

ADRs are **immutable once Accepted**: to change a decision, add a new ADR that
supersedes the old one (update the `Superseded by:` / `Supersedes:` headers on
both), rather than rewriting history.
The **decision** in an Accepted ADR is immutable: to change a decision, add a new
ADR that supersedes the old one (update the `Superseded by:` / `Supersedes:`
headers on both), rather than rewriting history.

*Editorial* edits that do **not** change the decision — fixing a typo, merging a
duplicate record, adding clarifying references — are allowed in place, provided
they are logged in a `## Revision history` table in that ADR so readers can still
distinguish the original accepted record from later non-normative edits.

## Index

Expand Down
Loading