Imported from yamchinsky/api-contract-reviewer-plugin (
skills/deprecation-policy/SKILL.md). Install upstream withnpx skills add yamchinsky/api-contract-reviewer-plugin --skill deprecation-policy. Copyright stays with the author.
name: API: Deprecation Policy description: Enforces the deprecate-then-remove flow for public symbols and routes. Use when reviewing PRs that remove an exported function/type or an HTTP route.
API: Deprecation Policy
Enforces the deprecate-then-remove flow for public symbols and routes.
Intent
Removal is the last step of deprecation, never the first. A consumer reading release notes — or @deprecated JSDoc in their IDE, or a Deprecation: header at runtime — has a chance to migrate. A consumer hit with a silent removal has no signal until production breaks. Every removed public surface must show a prior deprecation in its git history.
Rules
- Anything to be removed must first be marked
@deprecated <since version> — use <replacement>for at least one minor release before removal. - Deprecated runtime endpoints must return a
Deprecation: <date>header (RFC 8594) OR include_deprecated: truein the response body, so clients can detect the deprecation at runtime. - Silent removal (no prior
@deprecated) is a BREAKING finding under the breaking-change rubric. - Deprecation notes belong both in JSDoc on the exported symbol AND in the route / OpenAPI definition (
deprecated: trueor equivalent).
Good example
/**
* @deprecated since 1.4 — use `/v2/users`. Removal scheduled for 2.0.
*/
export function getProfile() { /* ... */ }
app.get(
'/v1/profile',
{ schema: { /* ..., deprecated: true */ } },
async (_req, reply) => {
reply.header('Deprecation', 'Tue, 01 Jul 2025 00:00:00 GMT');
// ... handler ...
},
);
Bad example
// PR deletes the /v1/profile route in a single commit.
// Git log shows no prior @deprecated marker on the handler or its docs.
// Old clients calling /v1/profile now get 404 with no migration path.
When this fires
- Removed routes or exports for which
git log -pof the deleted code does NOT show a prior@deprecatedannotation. - New deletions in a package's public
index.tswithout a deprecation cycle visible in the history. - Routes removed in a non-major version bump.
