ADR-14: Public-API deprecation policy (managed debt)¶
Status: accepted (2026-05-29) Blocks: workstream C (maturity), workstream E (bridge)
Context¶
The ecosystem house rule is “no dead code, no deprecated code, no backward-compatibility shims.” That rule is correct in steady state but wrong during a multi-release migration: replacing the nirs4all backend with dag-ml legitimately requires temporary compatibility code (a backend="legacy" path, dual-read bundle loaders, deprecated-but-still-working symbols). Codex flagged the blanket rule as counterproductive for the migration window.
Decision¶
For the migration window (until the G6 cutover completes), the absolute no-deprecated-code rule is replaced by a managed-debt policy. After G6, the absolute rule resumes.
Rules during the window:
Every Rust
#[deprecated(since = "X.Y.Z", note = "...")]must name a target removal version and link a tracking issue in the note.CI fails if any
#[deprecated]lacks a removal version, or if a release whose version ≥ the declared removal version still contains the symbol.Every deprecated public symbol must carry a removal-test (asserts the deprecation fires and the replacement works) until it is removed.
Production-path
TODOs must be justified:TODO(owner): reason (#issue). UnexplainedTODO/FIXMEon a production path fails the CI lint.nirs4all’s public API (frozen since 0.9.0) follows the same rule plus a minimum two-release working window before any removal, because external consumers (nirs4all-studio) depend on it.
Consequences¶
A CI lint (
scripts/check_deprecations.py, workstream C) parses#[deprecated]attributes and theTODOcorpus and enforces rules 1–4.The CHANGELOG records every new deprecation under “Deprecated” with its removal version, and every removal under “Removed.”
CONTRIBUTING.mddocuments the policy so a contributor knows a deprecation is a commitment, not a free escape hatch.
Risk¶
A managed-debt window can drift into permanent debt if removal versions slip. The CI gate (rule 2) is the backstop: a shipped removal version with the symbol still present is a hard failure, forcing the removal or an explicit ADR-superseder that re-schedules it.