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 DeprecationWarning from the old API. Document the rename in the docstring. Add a CHANGELOG entry.

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.

When a deprecation is unavoidable mid-cycle#

If a bug or security finding forces a behaviour change inside a PATCH release:

  1. The CHANGELOG entry under “Changed” explicitly names the behaviour change.

  2. If the public signature changes, the next MINOR release includes a deprecation shim under this policy. PATCH releases never break a signature.

If the change is forced by a downstream library (a sklearn or statsmodels deprecation cascading through the package), the CHANGELOG cross-references the upstream change.

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 emit DeprecationWarning is in scope for the next Wave-7 PR (ENG-22).

  • A tools/check_deprecations.py script will be added to list everything currently deprecated and its scheduled removal version. The script is run in CI; a deprecation past its removal version fails the build, so we cannot forget to delete the shim.

Cross-references#