Skip to content

Product Changelog vs. Main Branch Activity

LenserFight publishes two deliberately different pages, and conflating them is exactly the failure mode this page exists to prevent:

Product ChangelogMain Branch Activity
AudienceEnd users deciding whether to upgradeContributors, integrators, auditors
Authored byA maintainer, by handGenerated on every build
Source.changes/<pr-number>.md fragments, aggregated into dated version sectionsFull git history (main, first-parent) + GitHub PR metadata
ContainsWhat shipped: additions, fixes, security, deprecations, breaking changes, migration notesEvery PR/commit merged to main, whether or not it has shipped
UpdatedOnly when a maintainer runs pnpm changelog:cutEvery apps/docs build

A merged change is not a released change

Being merged to main means the change passed review and CI. It does not mean it has shipped to users, and it can still be reverted before anything ships. The Main Branch Activity ledger says this explicitly in its banner and labels every entry Unreleased, Released, or Internal — never inferred from the commit message, only from whether the commit is reachable from a published release tag.

Where the data comes from — and where it deliberately doesn't

We do not generate public prose from arbitrary commit messages. A commit subject tells you what a contributor typed, not what a user should be told, and it does not carry category, user impact, or verification evidence in a structured way. Instead:

  • Every user-facing pull request adds a .changes/<pr-number>.md fragment (schema: .changes/schema.json). This is the only source of prose for both pages.
  • .github/workflows/changelog-gate.yml blocks a PR that has neither a valid fragment nor an approved changelog:none label + reason.
  • Fields with no fragment/PR-metadata evidence render Not declared or Verification unavailable — never a guess.

Generation, not commit-back

tools/changelog/cli.mjs runs as a step in the docs project's Nx build/serve targets (apps/docs/project.json), writing JSON under docs/public/changelog-data/ (gitignored — never committed). Whatever platform builds apps/docs on every push to main regenerates this data as part of that same build; nothing is written back to git, so there's no bot-commit loop to guard against. See tools/changelog/ for the generation logic and its test suite.

Cutting a release — stamping the aggregated Unreleased fragments into a dated version section of the Product Changelog — is a manual step (pnpm changelog:cut <version>), run by a maintainer, then reviewed and merged like any other change. This is what "human-curated" means in practice: the platform never decides on its own that something is released.

Package changelogs stay separate

apps/cli/CHANGELOG.md, libs/sdk/CHANGELOG.md, and libs/adapters/connector/CHANGELOG.md are generated by Nx Release from conventional commits, exactly as before — this system doesn't replace or duplicate that. Product Changelog entries link to the relevant package changelog when a change is tied to a package release.

Legacy history

The old standard-version-generated CHANGELOG.md (85,000+ lines, with duplicated entries and unfiltered internal commits mixed into user-facing ones) was retired as the public-facing changelog because it had stopped being usable by the people it was meant to inform. It isn't in the working tree, but it's still recoverable from git history — see the root CHANGELOG.md for exactly how.