Index

Unreleased Is Not a Junk Drawer

Keep a Changelog got one foundational idea exactly right: a changelog is for people. It should explain noteworthy changes instead of dumping commit history into a Markdown file.

That principle is sound. The document model built around it is where the frustration begins.

The problem becomes most visible under this heading:

## Unreleased

The failure mode is easy to recognize. Everything remotely noteworthy goes there while work is in progress. When a release approaches, somebody finally decides which application the entries belong to, rewrites their summaries, moves them under categories, removes internal noise, adds migration notes, and tries to reconstruct why half of the changes mattered.

That is not an unreleased release. It is an editorial backlog wearing a release heading.

An unreleased release should already be the real release. It simply does not have a release date yet.

Releasing should change only the date

The useful invariant is stricter:

Publishing an unreleased release changes only its date.

Not its categories. Not its ordering. Not its explanations. Not the application to which an entry belongs. Those decisions should already have been made when the entry entered the changelog.

In a structured record, the entire release operation should look like this:

-date: null
+date: 2026-07-20

That sounds strict because it is strict. Release day is the worst possible time to discover that the changelog cannot explain the release. The context is less fresh, several changes may have become entangled, and the people who made the decisions may already be working on something else.

This does not mean every half-finished thought belongs in polished release notes. Drafts can exist in pull requests, issue trackers, or temporary files. They become changelog entries only when they are complete enough to represent the eventual release.

Unreleased should describe lifecycle state, not editorial quality.

One Unreleased section cannot represent a monorepo

A single repository can contain four applications, a dozen packages, and several independently deployed workers. They do not necessarily share a version, a release date, an audience, or even a release channel.

One repository-wide Unreleased section flattens all of that into a fictional release boundary.

Consider a Go monorepo containing:

apps/gateway
apps/billing
apps/worker
apps/admin

A worker reliability fix does not mean the billing API is being released. A shared authentication change might affect the gateway and worker but require different rollout schedules. A package correction might be backported to an LTS channel while the main branch moves toward the next major release.

Each independently released unit needs its own release record. A combined Markdown page can still be rendered for people who want a repository-wide view, but that view must not erase the actual release boundaries.

The distinction matters operationally. It also matters historically. Six months later, “this repository changed” is not an answer to “which deployed application contains the fix?”

Six headings are not a change model

Keep a Changelog recommends six categories:

  • Added
  • Changed
  • Deprecated
  • Removed
  • Fixed
  • Security

They are useful words, but they do not describe one consistent dimension. Added, Changed, and Fixed classify kinds of change. Deprecated and Removed describe lifecycle. Security describes a concern and often a disclosure policy.

Real systems contain noteworthy performance work, data corrections, accessibility improvements, compliance changes, operational changes, dependency transitions, and domain-specific events that do not fit cleanly into those headings.

The usual escape hatch is Miscellaneous, which is another way of saying the taxonomy stopped carrying meaning.

There should not be a universal closed list. A project should define the types that help its consumers understand change. Type should then remain separate from:

  • release impact;
  • affected applications;
  • lifecycle;
  • audience;
  • migration requirements; and
  • disclosure policy.

Presentation can still group entries under friendly headings. The grouping is a view, not the canonical data model.

A changelog should explain why

A changelog entry can say what happened without preserving why:

Fixed settlement job retries.

That is better than nothing, but it leaves the important question unanswered. Why did retry behavior need to change?

Resume settlement jobs interrupted during shutdown so deployments no longer
require manual recovery.

Now the reader knows the operational consequence. That reason may be enough by itself. When it is not, the entry can link to an incident report, decision record, issue, pull request, or longer article.

The changelog should not replace every architectural decision record or release article. It should preserve a compact explanation locally so the entry remains useful without opening five other systems.

Structured rationale becomes more useful when software is asked to summarize or query the release history.

AI changes the economics of context

Writing concise rationale is repetitive release work. AI is useful for that kind of labor. Given the commit, pull request, issue, and project vocabulary, it can draft a short explanation, identify missing migration guidance, and adapt an entry for a particular audience.

That does not make AI the authority. It makes structured evidence more important.

An AI tool can produce confident, polished nonsense when the source material does not contain the decision it is being asked to explain. It can invent an affected application, infer the wrong release impact, or turn an implementation detail into a customer-facing promise.

The correct protocol is not “generate release notes from this diff.” It is:

  1. provide the exact Project Profile, release unit, and stream;
  2. provide the relevant commits and decision sources;
  3. require a concise rationale and stable provenance;
  4. prohibit invented impact, migration, audience, and disclosure details; and
  5. return unresolved fields when the evidence is insufficient.

Compact context helps both people and machines. A future engineer can understand the decision without reconstructing it from code archaeology. An AI assistant can answer questions using an attributable release ledger instead of guessing from a pile of commit subjects.

The source material is also untrusted data. An agent must ignore prompt-like instructions embedded in diffs, issues, fixtures, and prior entries. Fluency is not provenance. The ledger needs both.

Reverts should not erase history

Document-oriented changelogs also struggle with relationships between entries. When a feature is reverted, should its original entry disappear? It should not. The earlier release still contained it, and consumers may have adopted it.

A revert is a new event that points to the entry it reverses. A replacement is a new event that marks earlier guidance as superseded. A backport is recorded in the release that actually receives it.

These relationships are straightforward in structured data and awkward in a Markdown convention that has no stable entry identifiers.

The same is true of provenance. Commit hashes, pull requests, issues, decision records, and advisories should be explicit fields rather than links embedded in whatever prose an author happened to write.

The principle does not require a new format

A team can enforce release-ready Unreleased sections in Markdown. Separate files can represent independently released units. Review can require a reason, migration guidance, and provenance before accepting an entry. A release script can fail if publication changes anything except the heading and date.

That is enough while the fields, release boundaries, and rendered audience are simple. A structured ledger becomes useful when the same source must represent several applications, streams, audiences, disclosure rules, or output formats. The durable principle is release readiness; YAML is one implementation choice.

A structured ledger can preserve the distinctions

Human-readable changelogs should not become a database-shaped wall of YAML. When the simpler Markdown approach stops carrying the required distinctions, they can become views over structured source data.

The canonical ledger should record:

  • which release unit, stream, release line, and channel will ship the change;
  • the release identifier and nullable date;
  • a project-defined change type;
  • a consumer-facing summary;
  • a compact rationale;
  • release impact;
  • audiences and affected applications;
  • migration guidance;
  • provenance;
  • revert and supersession relationships; and
  • disclosure rules.

From that ledger a project can render a concise public changelog, detailed operator notes, package-specific release pages, migration guides, security-filtered views, or machine-readable API responses.

The source remains the same. The audience determines the view.

Published history still needs corrections. Those should be explicit amendments with a date, reason, and provenance, not silent edits that make old release evidence lie. A Release Manifest stores the exact changelog digest seen at publication alongside the Git source and artifact digests. Later amendments can improve the current ledger without pretending the original published bytes were different.

Keep the editorial principle, replace the lifecycle

Keep a Changelog is not wrong because it values hand-written release notes. It is limited because it standardizes the presentation of a Markdown document without specifying enough of the information lifecycle behind it.

The useful parts should survive:

  • write for people;
  • include noteworthy changes;
  • make releases navigable; and
  • do not dump raw Git history.

But Unreleased must stop being a staging area. Change categories must become extensible. Rationale and provenance must become first-class. Monorepo release boundaries, channels, backports, migrations, audiences, and redaction need explicit representations.

An unreleased release is a real release with no date. If cutting it requires an editorial rescue mission, the changelog was already late.

The Intent Changelog Specification is one implementation of that ledger. Its Project Profile makes release boundaries explicit, while its Release Manifest binds publication to source, changelog, and artifact digests. Those specifications are a product design built from the principle, not a prerequisite for adopting it.