ADR 0012: Announce every removal through one advisory with a published horizon
Status
Accepted
Context
This package’s value is that established calls keep working. Public API compatibility is its first architecture characteristic after artifact integrity. Names therefore leave slowly: a renamed argument, a retired module, a getter whose service no longer exists.
Four spellings of “tell the caller something is going away” grew up
independently, and only one carried a date. A caller could not tell how long
they had, a maintainer could not audit what was due, and the warning category
was a per-author choice – which matters, because downstream projects run their
suites under -W error::DeprecationWarning.
ADR 0005 sets a removal date for legacy NWIS, but it is scoped to that adapter. Nothing recorded the general rule, and the deprecations kept accumulating.
Decision
Every deprecation is announced through the shared mechanism in
dataretrieval._deprecation, and every one has a published removal horizon
recorded in REMOVALS.
A deprecation advisory names three things: what is going away, what to use instead, and the date on or after which it may be removed. The mechanism tolerates an advisory with no date – it then promises nothing specific rather than implying a schedule it does not have. A deprecation of a public name is expected to carry one, and an advisory naming a replacement the caller cannot yet use is not finished.
REMOVALS is the single table of horizons. One table is auditable – what is
due can be listed, and a horizon can be extended in one place – whereas four
hand-rolled shims could only be found by grep. A renamed public argument keeps
working under its old name through one shared decorator rather than a shim
written for each getter.
The warning category an advisory carries is not the author’s choice, but the
rule setting it is not this record’s. ADR 0004: Use typed failures and bounded recovery decides
when an advisory is a DeprecationWarning (a name in this package is going
away) and when it is a DataCurrencyWarning (an upstream dataset has stopped
being updated). This record governs the mechanism and the horizon.
A horizon is a floor, not a schedule. Passing it permits removal; it does not require one, and removal remains a deliberate change with its own release note.
Consequences
A caller can see, from the warning alone, how long they have and what to move to.
Horizons can be audited and extended centrally, so a removal date cannot arrive unnoticed in a module nobody is reading.
Deprecating something costs more than adding a
warnings.warncall: the replacement must exist and a date must be chosen. That is the intended cost.The package accumulates long-lived compatibility shims. This is accepted – it is what the compatibility characteristic buys, and the table makes the accumulation visible rather than hidden.
Nothing is removed on the horizon alone. A removal still needs a release that says so.
Compliance
tests/deprecation_test.py covers the shared mechanism: that an advisory
names its replacement, and that the horizon it prints is the one in
REMOVALS. Per-surface tests assert the individual advisories, including that
a renamed argument still works under its old name. The warning category
assertions – that DataCurrencyWarning is not a DeprecationWarning
subclass – belong to ADR 0004: Use typed failures and bounded recovery.
Notes
ADR 0005 remains the record for legacy NWIS specifically, including its 2027-05-06 date. This record generalizes the mechanism without changing that decision.