Skip to content

fix(release): collapse synthetic version-bump entries in feeder-PR preview#469

Merged
goosewobbler merged 3 commits into
mainfrom
fix/preview-sync-collapse
Jun 29, 2026
Merged

fix(release): collapse synthetic version-bump entries in feeder-PR preview#469
goosewobbler merged 3 commits into
mainfrom
fix/preview-sync-collapse

Conversation

@goosewobbler

@goosewobbler goosewobbler commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #468. In standing-PR mode, the feeder-PR preview rendered a full changelog block (Changed → Update version to X.X.X) for every package a sync/lockstep bump carries along, instead of collapsing those no-real-change packages into the compact "Also bumped" list. A single-package PR (wdio example) drowned in ~10 placeholder blocks for untouched packages.

Root cause

The version engine mints a synthetic Update version to X placeholder for any bumped package with no conventional commits of its own (versionStrategies.ts, groupStrategy.ts, packageProcessor.ts). The preview formatter's compaction keyed off an empty changelog:

const packagesWithChangelog = new Set(
  versionOutput.changelogs.filter((cl) => cl.entries.length > 0).map((cl) => cl.packageName),
);

The placeholder makes entries.length === 1, so the package escaped the "Also bumped" list and rendered a full block. The tell: only the one package that reached the formatter with a genuinely empty changelog collapsed correctly; every other carry leaked the placeholder.

Fix

  • VersionChangelogEntry gains an optional synthetic flag (packages/core/src/types.ts), set at every minting site. Additive and optional — manifests written before it existed (absent flag = real entry) render exactly as before.
  • The formatter treats a changelog whose entries are all synthetic as "no real changes" — it collapses into "Also bumped" instead of a full block, via a hasRealEntries predicate replacing the bare entries.length > 0 checks.
  • The root lockstep bump is excluded from "Also bumped" at the list's definition, fixing a pre-existing leak in the non-sync branch (the sync branch already filtered it).

By construction a package's entries are either all-real or a single synthetic placeholder (the placeholder is only minted when extraction yields zero), so there is no mixed case to disambiguate.

Tests

packages/release/test/unit/preview-format.spec.ts — new block covering what the existing sync tests never exercised (synthetic entries actually present in changelogs):

  • synthetic-only carries collapse into "Also bumped"; the changed package keeps its full block; no Update version to noise leaks; root never listed.
  • all-synthetic output shows the "no individual changes" heading.
  • legacy placeholder without the flag still renders (back-compat).

versionStrategies.spec.ts updated to assert the flag is now minted.

Verification

pnpm turbo run lint typecheck test — green (32/32 tasks). No config-schema change, so no schema:gen/docs:config regen (the flag is on the runtime VersionOutput contract, not config).

🤖 Generated with Claude Code

Greptile Summary

This PR cleans up feeder-PR preview output for synthetic version-bump entries.

  • Adds an optional synthetic marker to changelog entries.
  • Marks fixed-group ride-along fallback entries as synthetic.
  • Collapses synthetic-only package changelogs into the compact bumped list.
  • Keeps changed packages and legacy placeholders visible.
  • Adds tests for mixed, all-synthetic, and empty-extraction cases.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
packages/core/src/types.ts Adds the optional synthetic changelog entry marker.
packages/release/src/preview/format.ts Uses non-synthetic entries to decide which package changelog blocks to render.
packages/release/test/unit/preview-format.spec.ts Adds preview coverage for synthetic-only carries and legacy placeholders.
packages/version/src/core/groupStrategy.ts Marks only unchanged fixed-group ride-alongs as synthetic fallback entries.
packages/version/test/unit/core/groupStrategy.spec.ts Adds group-strategy coverage for carry entries and empty extraction fallback behavior.

Reviews (3): Last reviewed commit: "fix(version): key carry-synthetic off me..." | Re-trigger Greptile

…eview

In standing-PR mode the feeder-PR preview rendered a full changelog block
(`Changed → Update version to X.X.X`) for every package a sync/lockstep bump
carries along, instead of collapsing those no-real-change packages into the
compact "Also bumped" list. A single-package PR drowned in placeholder blocks
for untouched packages.

The version engine mints a synthetic `Update version to X` placeholder for any
bumped package with no conventional commits of its own. The preview formatter's
compaction keyed off an *empty* changelog, so the placeholder (entries.length
=== 1) defeated it and the package rendered a full block.

Mark the placeholder structurally with a new optional `synthetic` flag on
VersionChangelogEntry, set at every minting site (sync/single/group/async). The
formatter now treats a changelog whose entries are all synthetic as "no real
changes" — collapsing it into "Also bumped" — and excludes the root lockstep
bump from that list. The flag is additive and optional: manifests written
before it existed render exactly as before.

Closes #468

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Standing release PR: #470 · v0.35.0 queued (4 packages) · open 39m · ✅ ready to merge

Release Preview — v0.34.0 → v0.35.0

Note: Labels on this PR are advisory in standing-pr mode. Bumps come from conventional commits in the standing PR; override by editing labels on the standing PR itself. Add release:immediate to bypass the standing PR and release this PR directly.

These changes will be added to the release PR (#470) when merged:

Changelog

monorepo v0.34.0 → 0.35.0

Added

Changed

Fixed

All packages → 0.35.0 (sync versioning)

  • @releasekit/version
  • @releasekit/notes
  • @releasekit/publish
  • @releasekit/release

After merge — predicted release

No version escalation — this PR's changes will be included in the queued release without affecting the projected versions.

Package Standing PR This PR After merge
monorepo 0.35.0 0.35.0 0.35.0

Updated automatically by ReleaseKit

Comment thread packages/version/src/core/versionStrategies.ts Outdated
Comment thread packages/version/src/core/versionStrategies.ts Outdated
Comment thread packages/version/src/package/packageProcessor.ts Outdated
… (Greptile)

Greptile flagged that marking the empty-extraction fallback `synthetic` in the
single and async strategies — and on the group strategy's extraction-error path
— over-reached. Those fallbacks represent the released package itself or a read
failure, not a lockstep carry, so collapsing them in the preview would hide a
real single/async release or make an extraction error look like a no-change
bump.

Narrow `synthetic` to the version-groups engine's clean empty-extraction path,
the only genuine lockstep carry. Single/async fallbacks and the group catch
path stay unflagged, keeping their visible changelog block. Add group-strategy
tests for both directions: carry → flagged, extraction error → unflagged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread packages/version/src/core/groupStrategy.ts Outdated
…utcome (Greptile)

Greptile flagged that extractChangelogEntriesFromCommits swallows git failures
and returns [] rather than throwing, so the prior `extractionFailed` guard could
not tell a no-change carry from an unreadable changelog: a group member with an
invalid/ambiguous revision gets [] with extractionFailed=false and was wrongly
marked synthetic (collapsed in the preview).

Key the synthetic flag off the authoritative signal instead — `isCarry`
(`!plan.changed`), a member that earned no releasable change of its own, the only
true fixed-group ride-along. A *changed* member that still comes back empty keeps
an unflagged, visible version-bump block. Ungrouped packages reach the changelog
path only when changed, so they pass isCarry=false.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@goosewobbler
goosewobbler merged commit 4d00095 into main Jun 29, 2026
26 checks passed
@goosewobbler
goosewobbler deleted the fix/preview-sync-collapse branch June 29, 2026 12:30
@github-actions github-actions Bot mentioned this pull request Jun 29, 2026
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.

Standing-PR preview shows full changelog blocks for sync-bumped packages (synthetic entries defeat 'Also bumped')

1 participant