Skip to content

Migrate changelog from single file to directory structure - #1552

Merged
sergey-shandar merged 1 commit into
mainfrom
claude/todo-changelog-directory-f47ma1
Aug 14, 2026
Merged

Migrate changelog from single file to directory structure#1552
sergey-shandar merged 1 commit into
mainfrom
claude/todo-changelog-directory-f47ma1

Conversation

@sergey-shandar

Copy link
Copy Markdown
Contributor

Summary

Restructure the changelog from a single CHANGELOG.md file into a per-version directory structure (changelog/) with individual version files and an unreleased/ subdirectory for pending changes. This eliminates merge conflicts on concurrent PRs and improves maintainability.

Key Changes

  • Removed CHANGELOG.md (2079 lines) and the todo/changelog-directory.md task (now completed)
  • Added changelog/ directory with:
    • README.md documenting the new layout and Keep a Changelog format
    • Individual version files (0.1.608.md through 0.44.0.md) containing release notes
    • unreleased/ subdirectory with per-PR files (e.g., 1547.md, 1542.md, etc.) for pending changes
    • .gitkeep to preserve the unreleased/ directory
  • Updated documentation references:
    • AGENTS.md: Updated changelog location reference
    • CONTRIBUTING.md: Updated changelog workflow instructions
    • todo/changelog-from-git-history.md: Updated cross-reference to the new structure
    • todo/changelog-website.md: Unblocked (no longer depends on the directory migration)

Implementation Details

The new structure follows Keep a Changelog conventions:

  • Each released version gets its own file (e.g., 0.44.0.md)
  • Unreleased changes are tracked in unreleased/<PR>.md files, one per PR
  • This eliminates the "merge conflict on every PR" problem where all changes were appended to the top of a single file
  • The README.md provides clear guidance on the layout and contribution workflow

https://claude.ai/code/session_01WQFBgRCxeiy5gw1is28t2H

Every PR used to add its entry at the top of `## Unreleased` in a single
2000-line file, so any two concurrent PRs conflicted on the same lines.

The changelog is now `changelog/`: one file per released version, plus
`changelog/unreleased/<PR>.md` for entries not released yet. PR numbers are
unique, so concurrent PRs can never conflict. Entry files hold list items
only — the version or PR number is the file name — and stay in the Markdown
subset the website will render with a self-hosted parser.

Released sections are retrofitted verbatim, one file per version.
`CHANGELOG.md` is a short stub pointing at the directory. AGENTS.md §8.3
(entry workflow), §8.4 (release step), §4 (documentation table), and
CONTRIBUTING.md describe the new layout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQFBgRCxeiy5gw1is28t2H
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@cloudflare-workers-and-pages

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
functionalscript 631223d Commit Preview URL

Branch Preview URL
Aug 14 2026, 03:18 PM

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Baseline origin/main = f04c670bfe3283dc0ea579aeae37b3f17667feb9; tested head 631223dd. This is the implementation of #1551, so I re-derived the mechanism rather than reading the migration.

Content preservation — mechanical, not by eye

I reconstructed the changelog from the new tree and compared it to main's CHANGELOG.md programmatically.

Released sections: byte-identical, all 96.

old released sections: 96, new version files: 96
no file for old section: []
file with no old section: []
released sections NOT byte-identical (trimmed): 0
non-list top-level lines in released bodies: 0

Every ## X.Y.Z body in main equals changelog/X.Y.Z.md exactly after trimming the surrounding blank lines — same characters, same entries, same order. Nothing reworded, merged, dropped, or reordered in released history. 0.1.608 was the one empty section in main and is the one empty file here, which is exactly the "empty <version>.md retrofits a released section that recorded no entries" case the new README documents.

Whole corpus conserved:

total entries in old CHANGELOG.md: 461
total entries in new corpus:       461

The ordering deviation, quantified

changelog/unreleased/ holds 25 files carrying 30 entries. Concatenating them in descending PR-number order, exactly as changelog/README.md and §8.4 now specify, gives:

unreleased: old entries 30, new entries 30, files 25
entries only in old: 0; only in new: 0
entries at a different index: 15 of 30

So the entry set is identical — the reorder is the only change — and 15 of 30 entries move. The cause is that main's ## Unreleased is in merge order, not PR-number order; the old sequence has 6 adjacent ascending steps:

[1547,1547,1546,1548,1548,1545,1544,1543,1542,1542,1541,1538,1539,
 1530,1540,1536,1537,1533,1534,1531,1527,1526,1526,1520,1520,1525,
 1522,1519,1516,1514]

(1546<1548, 1538<1539, 1530<1540, 1536<1537, 1533<1534, 1520<1525.)

This is the deviation #1551 was approved on, and I am glad to see it is stated rather than glossed: changelog/README.md says "Entries are therefore ordered by pull-request number, not by merge order — a pull request opened earlier can merge after one opened later. The deviation is accepted." Visible and intentional, which is what I asked for. Within each PR's own file the relative order of that PR's entries is preserved (checked for all 25 files).

There is no generator script to run — the release step is a documented manual concatenation. I simulated precisely that procedure, and the numbers above are its output.

§8.3 rules survive the move

  • PR-only links: 461 entries, 3 with no /pull/ link — the same 3 pre-convention entries main carries — and 0 non-/pull/ links anywhere in the entry corpus. Main's only two non-/pull/ links were preamble boilerplate (Keep a Changelog, SemVer); they moved into changelog/README.md, which is not an entry file. Clean.
  • Released sections not rewritten: proven above by the byte-identity result.
  • Unreleased vs released distinction preserved: the ## Unreleased heading becomes the unreleased/ directory, released sections become <version>.md. §8.4's version-bump table was updated in step (changelog/unreleased/ contains …), so the rule that decides which number moves still has a well-defined subject.
  • New "list items only, no heading inside a file" rule: holds — 0 of the 121 files contains a Markdown heading.

Rest of the battery

  • Diff is Markdown-only plus changelog/unreleased/.gitkeep; no package.json, no CI, no generated files, so no tsc/prepack/drift gate is in scope. files is ["**/*.js","**/*.d.ts","**/*.mjs","**/*.d.mts"], so neither the old CHANGELOG.md nor the new directory is published — no packaging impact.
  • node bin/linkcheck.mjs output is identical to origin/main's, line for line. Deleting todo/changelog-directory.md and rewriting the CHANGELOG.md references stranded nothing.
  • No code, CI workflow, or the website generator reads CHANGELOG.md, so the stub does not break a build step.
  • No entry for this PR, correctly — §8.3 exempts documentation-only changes.

One observation, not a request: a directory listing sorts 0.10.0.md before 0.2.0.md, so browsing changelog/ no longer shows versions newest-first the way the single file did. todo/changelog-website.md is where that gets solved, and nothing here depends on it.

@sergey-shandar
sergey-shandar added this pull request to the merge queue Aug 14, 2026
Merged via the queue into main with commit 73e1609 Aug 14, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants