Stability and deprecation policy¶
This page is the contract between Tripack and its users about what is part of the public API, how it is versioned, and how long it takes between announcing a deprecation and removing the deprecated symbol.
Public API surface¶
A symbol is part of the public API if and only if all of the following are true:
- it lives in one of the three published packages
(
tripack-contracts,tripack-runtime,tripack-container); and - it is re-exported via
__all__from that package's top-level__init__.py; and - its name does not start with an underscore.
Anything else - including imports that are technically reachable but
not listed in __all__, modules under _private/, and the entire
internals of tripack-runtime accessed bypassing
tripack-container - is internal and may change at any time
without prior notice.
The public API is rendered at https://goabonga.github.io/tripack/ and mirrored in the docstrings shipped with each wheel.
Deprecation lifecycle (n + 2 minors)¶
Tripack follows Semantic Versioning per
package - see
CONTRIBUTING.md
for the full commit-type to bump-level mapping. Removals of public
symbols are governed by the cycle below.
The cycle is counted in minor versions, not majors. Letting M
be the current major and m the current minor of a package:
| Version | What changes |
|---|---|
M.m.* |
The feature exists. No warning. |
M.(m+1).0 (next minor) |
The feature is deprecated. The announcement is a deprecate(<package>): ... commit - a custom Conventional Commits type registered in multicz.toml that bumps the minor and routes the entry into ### Deprecated of CHANGELOG.md. The code raises a DeprecationWarning on use, the migration path is documented on the site, and the feature still works. |
M.(m+2).0 (second minor after deprecation) |
The feature is removed. The commit type is remove(<package>): ... - another custom multicz type that bumps the minor and routes to ### Removed in CHANGELOG.md. Under the n+2 contract, a removal that respected the warning window is not a breaking change (consumers had two minor releases to migrate), so the major number M does not change. The Removed entry back-links to the original Deprecated entry. |
Concretely:
- "n + 2" means two minor releases between announcement and
removal. Patches (
M.m.z) never deprecate or remove. Majors ((M+1).0.0) are reserved for the bypass case below. - The announcement and warning land in the release that introduces them - never in an earlier release.
- Code that triggers the deprecation continues to work until the second minor after the announcement. Don't skip the warning phase.
- The announcement commit uses the
deprecate:type (notfeat:). The removal commit usesremove:(notfeat:and notfeat!:). Both are custom types declared inmulticz.tomlunder[project.bump_rules], both bump the minor, and both route to a dedicatedCHANGELOG.mdsection (### Deprecatedand### Removedrespectively). See the full mapping inCONTRIBUTING.md. feat!:/BREAKING CHANGE:(and therefore a major bump) is reserved for changes that bypass the n+2 minor window - security fixes, fundamental design errors that cannot wait two minor cycles.
Exceptions¶
- Security fixes may remove a vulnerable symbol without the deprecation window. The release notes explain why and link to the advisory.
- 0.x releases (the current state of all three packages) follow a relaxed cycle: a deprecation introduced in v0.(y+1) may be removed in the same v0.(y+1) line, since semver explicitly allows breaking changes during the 0.x phase. The n+2 promise becomes binding at v1.0.
How to deprecate (for maintainers)¶
Emit a DeprecationWarning from the deprecated entry point with
stacklevel=2 so the warning points to the caller, not to the Tripack
internals:
import warnings
def old_resolver():
warnings.warn(
"tripack.old_resolver is deprecated; use "
"tripack_container.Container.resolve instead. "
"Will be removed in tripack-runtime v1.3.0.",
DeprecationWarning,
stacklevel=2,
)
...
The warning message MUST name:
- the deprecated symbol;
- the replacement (or "no replacement, drop the call");
- the target removal version.
Checklist for a deprecation commit:
-
DeprecationWarningraised withstacklevel=2 - Warning text names replacement + target removal version
-
packages/tripack-<name>/CHANGELOG.mdentry underDeprecated - Zensical page updated with the migration path
- Conventional Commit type for the announcement is
deprecate(<package>): ...(custom type, minor bump, routed to### Deprecated). - Conventional Commit type for the removal, two minors
later, is
remove(<package>): ...(custom type, minor bump, routed to### Removed). Reservefeat!:/BREAKING CHANGE:only when the removal bypasses the n+2 window.
How to ride deprecations safely (for consumers)¶
Pin to the minor of each Tripack package, not only the major:
Promote DeprecationWarning to errors at least once per minor bump in
your test suite so upcoming removals fail loud before they actually
land:
Read the per-package CHANGELOG.md before every bump - every removal
is listed under a Removed section and back-references the original
Deprecated entry.