Skip to content

Change logs: assemble component change-log fragments at release time and check readiness before tagging - #1612

Merged
longquanzheng merged 3 commits into
mainfrom
chore/changelog-fragments-components
Nov 11, 2026
Merged

longquanzheng merged 3 commits into
mainfrom
chore/changelog-fragments-components

Conversation

@longquanzheng

@longquanzheng longquanzheng commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Component change logs now come from fragments, as the skills change log does
since #1609. A pull request that changes a component adds a uniquely named
fragment under changelog.d/<target>/. It no longer edits the newest entry of
docs/reference/<component>/changelog.mdx or agents/CHANGELOG.md. A
release-prep pull request writes each release entry before the tag.

This pull request is based on main. It is no longer stacked on #1609, which
is merged.

  • New targets. changelog.d/ gains go, java, python, rust,
    typescript, web, cli, server, agents (the docs change log), and
    agents-packages (agents/CHANGELOG.md).
    • Their fragments take a section front matter key: Breaking, Added,
      Changed, Deprecated, or Fixed. agents-packages may also name a topic,
      such as Dex MCP conventions.
    • Fragments for docs change logs follow the docs prose rules: no inline
      backticks, and no braces or <.
    • new <target> --section <section> writes the skeleton.
  • prepare <components> --version <V> --date <D> [--allow-empty] writes
    the release entries. Its logic is in the new
    script/release/component_changelogs.py.
    • A new minor gets a new entry. So does each server-zd 0.1.N and each
      agents package release in agents/CHANGELOG.md. The heading, anchor,
      and Released line follow the existing format.
    • A patch folds into its minor's entry. The Released line lists the patch,
      and its items end with "Since 1.NN.P".
    • Preparing the same version again folds late fragments into that entry.
    • --allow-empty writes "No user-visible changes." A later prepare of the
      same version that adds items removes that line.
    • The first run absorbs the entries already marked unreleased on main and
      keeps their section order. A release that does not match such an entry
      fails. For example, 1.44.1 while main holds unreleased 1.45 fails: the
      message says main ships that entry as 1.45.0, so release 1.45.0 or first
      move its items into fragments. These are "Not released yet" in the docs
      change logs, ## Unreleased, and ## 0.5.0 (not released yet).
    • Older entries and Reference: links stay byte-identical.
    • agents prepares both agents change logs.
  • verify-release-prep checks every target that a labelled pull request
    touches. It takes each target's version and date from that target's own
    newest Released line or heading. It reruns prepare on the base and
    requires byte-identical output. When the base gained a fragment, it fails
    and prints the exact re-prep command.
  • check-ready <component> <version> fails while a target still has
    fragments, or while its newest entry is unreleased or is not the target
    version. It prints the prepare command.
    • It parses the entry's Released line. Every mention must name the right
      tag with a calendar date and its release URL, with / encoded as %2F.
      A missing or malformed Released line fails. The agents package heading
      needs a valid date.
    • script/release/changed_components.py calls it for every selected
      component. Release changed components therefore fails its plan
      before creating any tag.
    • server-zd-binary-release.yml and server-zd-image-release.yml call
      it on the tagged commit in their metadata jobs. A failure stops the
      binary build, asset upload, and reference snapshot, and the image build
      and push. Its message says the entry must be
      merged to main before the tag: delete the release and its tag, merge the
      release-prep pull request, and tag again.
  • check-pr rejects edits to any component change log unless the
    description contains a line changelog: correction: <reason>.
    • Pull requests up to LEGACY_CHANGELOG_PR_MAX may edit only the newest
      unreleased entry, or open one above the released entries. They may do so
      only while that target has no fragments.
    • Under that rule, the unreleased entry's version must stay newer than the
      newest released entry, and must not move back from the base's unreleased
      version. Reopening or moving back to a released version fails.
  • Snapshot compare links. The reference-snapshot compare links in
    release-changed-components.yml and server-zd-binary-release.yml prefill
    changelog: correction: reference snapshot. A snapshot may rewrite links
    in a change log.
  • Frozen files. The five sdk-*/CHANGELOG.md files now point to the
    docs change logs. They only held a never-stamped ## Unreleased section
    that duplicated the docs change logs. Nothing in .github/ or package
    metadata reads them.
  • Rules and docs. The new rules are in "Change Logs" in CLAUDE.md,
    AGENTS.md, and .cursor/rules/project-core.mdc. The patch fold-in
    sentence, CONTRIBUTING.md Releases, docs/README.md,
    changelog.d/README.md, and the pull request template are updated too.
  • CI triggers. Release Tooling CI also runs when a change log changes,
    because a test prepares every current change log.

Why

Concurrent pull requests insert entries at the same spot of the same files.
In the last three weeks, agents/CHANGELOG.md changed in 48 commits and
docs/reference/web/changelog.mdx in 25. #1574 and #1598 both created the
## 1.45 section in five SDK change logs and conflicted in all five. Release
stamping pull requests, such as #1576, touch the same region again.

Fragments have unique names, so concurrent pull requests never touch the same
path. The rule "the change-log entry is on main before the tag" holds
mechanically. The release-prep pull request writes the final entry with its
Released line before the tag. The release then snapshots the reference from
main with that entry, and the preflight refuses to tag without it.

Compatibility

  • Existing change logs keep their format. The first prepare turns each
    current unreleased entry into the release entry.
  • Open pull requests numbered up to LEGACY_CHANGELOG_PR_MAX keep working
    while their target has no fragments.
  • Release cutters gain one step: merge the release-prep pull request before
    dispatching Release changed components or creating a server-zd/v
    Release.
  • No skills content changes, so this needs no skills release.

Testing

  • make release-tooling-test runs 83 tests.

    • New: script/release/component_changelogs_integ_test.py, with 21
      fixture-repo integration tests:
      • lint, including the docs prose rules;
      • new --section;
      • legacy absorption and versioned unreleased headings;
      • patch fold-in and same-version re-prep;
      • --allow-empty;
      • older-version and mismatched-legacy errors;
      • server-zd entries per release;
      • agents preparing both files;
      • check-ready, with Released-line parsing (an unencoded URL, an
        impossible date, a wrong tag, another version, a malformed line, a
        missing line, and a folded patch);
      • placeholder removal on re-prep;
      • the unreleased-version mismatch message;
      • the failing check-ready in the metadata job of both server release
        workflows, which every later job needs;
      • verify-release-prep across several components, with tampering and a
        moved base;
      • check-pr with a correction line, the narrowed grace, and grace
        version keys that move back;
      • prepare and check-ready on every current change log.
    • Updated: changed_components_integ_test.py. Its fixtures write ready
      change logs, and new cases fail on pending fragments, a missing entry, a
      stale entry, and a Released line naming the wrong tag.
  • A dry run on a copy of current main ran:

    • prepare go,java,python,rust,typescript,web,cli --version 1.45.0 --allow-empty
    • prepare server --version 0.1.26
    • prepare agents --version 0.5.0

    After it:

    • check-ready passed for every component.
    • check-pr --labels release-prep passed.
    • agents_release_notes.py 0.5.0 extracted the new section.
    • cd docs && npm run check passed.
  • cd docs && npm run check passes on this branch.

  • Skills check-package.py, check-doc-map.py, and the skills unit tests
    pass, as do make copyright-check and make ci-runner-check.

  • check-pr on this branch against origin/main passes.

  • CI runs Check Gate and Release Tooling CI.

skills-release: no bump needed: release tooling and contributor rules only; no skill content changes

…rep pull request

Pull requests that change a component edited the same newest entry of each
change log, so concurrent pull requests conflicted there. The component
targets go, java, python, rust, typescript, web, cli, server, agents, and
agents-packages now take fragments under changelog.d/<target>/ with a section
front matter key, linted with the docs prose rules for the docs change logs.

prepare <components> --version --date writes each release entry: a new entry
per minor (per 0.1.N for server-zd, per release for agents/CHANGELOG.md), a
patch folded into its minor with "Since" items, a repeated prepare folded into
the same entry, and the existing unreleased entries absorbed on the first run.
verify-release-prep checks every target the pull request touches against
prepare on its base. check-ready fails the Release changed components plan
while a selected change log does not record the release; the server binary
release only warns. Grace pull requests may edit only the unreleased entry.

Snapshot compare links prefill the changelog: correction line, and the five
sdk-*/CHANGELOG.md files now point to the docs change logs.
@longquanzheng longquanzheng added type:chore CI, build, release, or tooling P2 Normal priority area:ci Component: ci area:docs Component: docs size:M A few days labels Nov 11, 2026
@codecov

codecov Bot commented Nov 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…and parse Released lines

- The server binary release now fails in its metadata job when check-ready
  does not find the entry, before any build, upload, or snapshot. Its message
  says to delete the release and tag, merge the release-prep pull request,
  and tag again.
- check-ready parses the Released line of the newest entry and validates each
  date, tag, and release URL, and the agents package heading date.
- A same-version prepare that adds items removes "No user-visible changes.".
- A release that does not match the unreleased entry on main names the
  version main ships instead.
- Under grace, the unreleased entry's version key must stay newer than the
  newest released entry and must not move back from the base's key.
The image release runs the same check-ready step on the tagged commit in its metadata job, so a missing entry stops the build and push, as in the binary release.
@longquanzheng
longquanzheng merged commit d296824 into main Nov 11, 2026
67 of 72 checks passed
@longquanzheng
longquanzheng deleted the chore/changelog-fragments-components branch November 11, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ci Component: ci area:docs Component: docs P2 Normal priority size:M A few days type:chore CI, build, release, or tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant