dependency-upgrade-management · git:20260809.21f29b0 · 2026-08-09 · sha256 fdd87254f98a4099

dependency-upgrade-management git:20260809.21f29b0A

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

---
name: dependency-upgrade-management
description: Discipline for keeping dependencies current and deprecating capabilities safely — an inventory (SBOM) of what's actually shipped, security patches on a fast lane separate from routine/major upgrades, and a stated deprecation window (Sunset/Deprecation headers, N-2 support) before removing anything consumers rely on. Use when upgrading a dependency, triaging a Dependabot/Renovate PR, deciding whether an upgrade is safe to automerge, or planning to deprecate or remove a capability others depend on.
---

# Dependency & Upgrade Management

A dependency is code you didn't write but do ship — it needs the same update discipline as your own code, except split into lanes by risk: a security patch and a major-version upgrade are different kinds of change with different urgency, and treating them identically means either shipping security fixes too slowly or shipping breaking changes too casually.

## Phase 1 — Know what you ship (SBOM)

Before triaging any upgrade, the project needs an accurate inventory of its dependency tree, not just its direct `package.json`/`requirements.txt`/`Cargo.toml` entries — transitive dependencies carry just as much risk and are the ones people forget about.

- Generate a **Software Bill of Materials** (SBOM) in CycloneDX or SPDX format as part of the build, not as a one-off manual export — an SBOM that's stale by the next release doesn't answer "what are we actually running" when a new CVE drops.
- The SBOM is what a dependency-vulnerability scan (see `secure-coding`'s Phase 4) runs against — inventory and scanning are two steps of the same discipline, not separate concerns.

## Phase 2 — Two lanes, not one queue

Route every proposed upgrade (automated PR or manual bump) into the lane that matches its risk:

| Lane | Trigger | Review depth | Cadence |
|---|---|---|---|
| **Security fast-track** | a CVE against a version currently in use | automerge if it's a patch-level bump with a passing test suite and a short observation window; manual review only if it's also a major bump | immediate, outside the batch schedule |
| **Routine batch** | non-security patch/minor bumps | grouped, reviewed together, low ceremony | weekly or similar fixed cadence — batching avoids a constant trickle of one-line PRs eating review attention |
| **Major-version migration** | a major version bump, even with no known CVE | full review: read the changelog for breaking changes, run the full test suite, check every usage site the upgrade touches | deliberate, scheduled, never auto-merged |

A security fix that also happens to be a major bump does not get the fast-track's automerge — the urgency of the CVE doesn't remove the risk of the breaking change; it goes to manual review, expedited.

## Phase 3 — Deprecating something others depend on

The same discipline a dependency owner owes you, you owe your own consumers (internal teams, API clients, plugin authors) when removing a capability:

- Signal the deprecation before removal — for an HTTP API, the `Deprecation` and `Sunset` response headers (RFC 8594 / RFC 9745) plus a `Link` header pointing at migration docs; for a library, a deprecation warning at the call site plus a changelog entry.
- State a concrete removal date in the signal, not "in a future release" — an open-ended deprecation trains consumers to ignore the warning, since there's no deadline forcing action.
- Support the old and new path simultaneously during the window. A common baseline is **N-2**: support the current version plus the two prior ones, so a consumer has a real runway rather than a single release cycle to migrate.
- Only remove the deprecated path after the stated sunset date has passed — removing it early because "surely nobody's still on it" breaks whoever didn't get the memo in time, which is exactly the failure this phase exists to prevent.

## Phase 4 — Safe major-version migration (as the consumer)

When upgrading a dependency across a major version, in order:

1. Read the changelog for breaking changes, not just the version number's assumption of "probably fine."
2. Check the codebase for every usage site the breaking changes actually touch — a global search for the API surface that changed, not a spot check.
3. Apply the vendor's codemod/migration tool if one exists; hand-port only what it can't cover.
4. Run the full test suite (leaning on `tdd`'s suite, not just the changed area) before merging.
5. Where the ecosystem supports it, roll the upgrade out to a subset of traffic/environments first (the same progressive approach as `safe-deployment`) rather than flipping every consumer to the new major version at once.

## Done when

- [ ] The project's SBOM reflects the current dependency tree and is regenerated as part of the build.
- [ ] Every open upgrade PR is in the lane matching its actual risk, not queued generically.
- [ ] No capability was removed without a prior deprecation signal carrying a concrete removal date and a support window.
- [ ] A major-version upgrade was reviewed against its changelog and every real usage site, not merged on the strength of a passing CI run alone.