deprecation-program · git:20260728.fac4544 · 2026-07-28 · sha256 0f89abbba3ca963a

deprecation-program git:20260728.fac4544A

Immutable. This exact content is served forever at /api/v1/blob/0f89abbba3ca963a.

---
name: deprecation-program
description: Run a deprecation from usage telemetry through a hard sunset date, with migration tooling and staged comms, so a system retires without stranding its callers. Use when you own an API, endpoint, library, or service that must be turned off while other teams still depend on it.
---

# Deprecation program

A deprecation announcement changes nobody's behavior. Teams migrate the week
their code breaks, not the week you ask, so a "deprecated" label with no
telemetry, no tooling, and no off switch becomes a maintenance tax you pay
indefinitely. Run it as a program with a burndown and a real end date, not a
wiki page and good intentions.

## Method

1. **Instrument the surface before you say a word.** Add per-caller telemetry:
   which team, service, and code path hits it, and at what rate. Tagged access
   logs or OpenTelemetry spans beat an aggregate counter, because "2M calls a
   day" names nobody to email. You cannot deprecate a caller you cannot
   identify.
2. **Publish a notice carrying a hard date and the replacement.** State the
   exact date the system stops answering, the migration target, and the reason.
   Emit the warning at the call site too: a `Sunset` response header (RFC 8594),
   a `@Deprecated` annotation, a startup log line. A notice with no date is a
   wish.
3. **Ship the migration, not just the docs.** Write the codemod (jscodeshift,
   OpenRewrite, a scripted sed pass), the shim, or the adapter that does the
   mechanical rewrite. Every hour of toil left on a caller multiplies by the
   caller count; a codemod serving three teams has already paid for itself.
4. **Close the front door the day you announce.** Block new adopters at once: a
   lint rule, a denied build dependency, a registration flag that refuses fresh
   integrations. A "deprecated" system still gaining callers is not being
   deprecated, and the newcomers shout loudest when the date lands.
5. **Burn the list down with comms tied to the telemetry.** Track remaining
   callers as a countdown and mail the specific teams on it at 90, 30, and 7
   days, not a broadcast channel nobody reads. When a team stalls, escalate to
   its manager with the exact call counts your instrumentation produced.
6. **Rehearse the shutoff with a reversible brownout.** Before the real date,
   fail all calls for a scheduled hour, then restore. Stragglers feel the break
   while you can still undo it, and hidden dependencies surface before they
   become an outage. Keep a logged, expiring break-glass path for true
   emergencies.
7. **Delete the code and tombstone the address.** Remove the implementation and
   leave a clear error at the old entry point pointing at the replacement. Code
   kept "just in case" gets re-adopted and quietly un-deprecates itself, so
   close the program by making the old path impossible to return to.

## Checks

- Can you name every team calling the system this week from telemetry, rather
  than guessing from memory?
- Does the notice carry a specific off date and a migration path a caller can
  complete without opening a ticket to you?
- Is a brand-new caller blocked from integrating today, or can the list still
  grow under you?
- Did a timed brownout rehearse the shutdown before the real one fired?

## Boundaries

This covers retiring a system you own that has external callers. A purely
internal refactor with no downstream consumers needs none of the ceremony. A
security kill switch that must fire now overrides the comms calendar: run your
incident process, not a 90-day burndown. Match the notice window to your
organization's API deprecation policy and any contractual commitments to
customers.