Deprecation Policy#
Note
This document is the canonical policy for retiring public API in
process-improve. Tracks
ENG-22.
Scope#
This policy covers anything documented as public:
Top-level imports (
process_improve.PCA,process_improve.lm).Public methods and attributes on documented classes (
PCA.scores_,PLS.predict,MCUVScaler.fit).The public signatures of those methods (kwarg names, defaults, keyword-only-ness).
The MCP tool surface declared via
@tool_spec: tool names, schema keys, and the meaning of each field.
Private API (anything prefixed with _, anything under
process_improve._internal or process_improve._linalg,
and anything not re-exported from a package __init__.py) may
change without notice.
The contract#
For any breaking change to a public surface, follow this schedule:
Phase |
At least one MINOR release each |
What contributors do |
|---|---|---|
Announce |
X.Y.0 |
Add the new API. Emit a
|
Warn |
X.(Y+1).* and on |
Old API still works; the warning still fires. CHANGELOG carries “Deprecated since X.Y; will be removed in (X+1).0”. |
Remove |
(X+1).0 |
Old API is deleted. CHANGELOG entry under “Removed”. |
In words: one MINOR cycle of “you can keep using this, but here is the new name” plus a second cycle of “we mean it” before removal at the next MAJOR.
Mechanism#
A renamed attribute or function uses the helper
warnings.warn from the standard library with the
DeprecationWarning category and stacklevel=2 (consistent
with Error-Handling Style Guide):
import warnings
def old_name(*args, **kwargs):
warnings.warn(
"process_improve.X.old_name is deprecated since 1.23.0 "
"and will be removed in 2.0; use X.new_name instead.",
category=DeprecationWarning,
stacklevel=2,
)
return new_name(*args, **kwargs)
Required fields in the message:
The fully qualified deprecated name.
The version that announced the deprecation (
deprecated since X.Y.0).The version that will remove it (
will be removed in (X+1).0).The intended replacement (or “no replacement; the functionality is no longer supported”).
For renamed attributes on PCA / PLS / TPLS, the existing
__getattr__ migration helper is the right mechanism; it
should be updated to emit a DeprecationWarning rather than
raising immediately. The helper is a single place to enforce
the message format.
Changing a default#
A new default that changes the numbers a call returns, rather than retiring a name, follows the same schedule. Its risk is different: code that keeps running, now on other results, is wrong without being broken. So:
The parameter’s default becomes
None, which resolves to the old value until(X+1).0and to the new one from then.The warning is a
FutureWarning, not aDeprecationWarning. Python shows aFutureWarningto end users by default; it hides aDeprecationWarningoutside__main__and test runs, so the people whose results will change would never see it.It is issued only by calls whose result the new default would change, and passing the parameter, to either value, silences it. A call the change leaves alone stays quiet.
Where the result is a dict that an agent or a tool reads, it also carries the warning’s text (as
analyze_experiment’scoding_notedid), since a warning does not reach them.Where possible, the new behaviour keeps what the old one gave, under an unmistakable name (
coefficients_actual), so that nobody loses a result they relied on.At
(X+1).0the default becomes the new value, and the warning and the note are removed.Nonestays accepted, as the new value, where a caller or a tool schema can still pass it.
analyze_experiment’s coding was the first example: announced in
1.98.0, its default changed from "actual" to "auto" in 2.0.0.
What is not a breaking change#
Adding a new optional kwarg with a default that preserves the previous behaviour.
Adding a new public function.
Fixing a documented bug (the fix is the breaking change of the bug, not of the API).
A purely internal refactor that does not affect any public surface.
Edge case: Bunch return types. The fitted-model predict
methods return sklearn.utils.Bunch with named fields. Adding
a field is not a breaking change. Renaming or removing one
is.
Tracking and rollout#
The
__getattr__migration helpers on PCA / PLS already exist; they currently raise rather than warn. Migrating them to emitDeprecationWarningis in scope for the next Wave-7 PR (ENG-22).tests/test_deprecation_policy.pyreads everywarnings.warn(..., DeprecationWarning)call insrc/and checks its message against the format above, so the message is written as a string literal (an f-string is fine) where the call is made. It also compares the removal version with theversioninpyproject.toml: once the package reaches it, the test fails, so we cannot forget to delete the shim. The test runs in CI with the rest of the suite.
Cross-references#
Error-Handling Style Guide – warnings categories,
stacklevel, thewarnings.warnpattern.Reproducibility Contract (RNG Handling) –
random_statemigrations follow this policy.Keep a Changelog - the format the project’s CHANGELOG follows.