Skip to content

feat(changelog): dedupe generated entries against curated lines and repeated subjects - #7

Merged
bytesnail merged 2 commits into
mainfrom
feat/changelog-dedupe
Oct 5, 2026
Merged

bytesnail merged 2 commits into
mainfrom
feat/changelog-dedupe

Conversation

@bytesnail

@bytesnail bytesnail commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

What

Adds automatic deduplication to the changelog draft generator (scripts/changelog.ts), verified against this repo's real CHANGELOG.md:

  1. Hash claims (primary mechanism). A curated entry claims the commits it covers with backtick hashes, e.g. … as described. (\aaa1111`)(multi-hash forms like(`aaa1111`, `bbb2222`)work; abbreviated and full hashes prefix-match each other). The generator skips claimed commits. This is the only deterministic way to dedupe real curated prose, which is worded nothing like the commit subjects — confirmed by simulating the script on the current[Unreleased]` section (the mtime-poll fix and the hermetic-tests commits were drafted next to their own hand-written entries).
  2. Text matching (hardened). dedupeKey(entry) normalizes for comparison: strips the leading - , trailing commit-hash annotations, GitHub's (#N) squash-merge suffix, trailing punctuation, and case. Generated entries matching a curated line, or repeating an earlier same-subject commit (oldest kept, cross-bucket), are dropped.

The current [Unreleased] entries are annotated with claims per the new convention (visible in the diff of CHANGELOG.md); claims may be trimmed at release review like any generated hash annotation.

Verification

Simulated renderChangelog on the real repo state (version 0.5.1, range v0.5.0..HEAD): before, the draft contained 3 semantic duplicates of the 2 curated entries; after, 78134e8/8bdfe06/d0cb49f are skipped and all other commits still draft.

Behavior contract (unchanged)

  • chore: release commits still excluded; re-runs still no-op once the section exists; bucket-merge logic untouched.
  • No package.json version bump (per repo policy; semver level for the next release: minor, this is a feat).

Tests

  • dedupeKey normalization (hashes, PR refs, punctuation, case, prefix-only lookalikes kept).
  • Hash claims: differently-worded claim on a continuation line, multi-claim entry, full-hash claim matching abbreviated %h, unclaimed sibling kept, claims carried verbatim.
  • Text dedup: curated duplicate dropped, repeated subject keeps oldest, cross-bucket duplicate dropped, (#N) suffix does not defeat matching.
  • Full suite: 86/86 pass; tsc --noEmit clean.

Docs: AGENTS.md changelog-writeup synced (READMEs only link CHANGELOG.md, no change needed).

…epeated subjects

Draft entries are normalized (bullet, trailing commit-hash annotation,
punctuation, case) into a dedupe key; a commit is skipped when its text
already appears as a curated [Unreleased] bullet or repeats an earlier
commit's subject (oldest kept, cross-bucket).
Verified against the actual CHANGELOG.md: curated prose is worded nothing
like the commit subjects it covers, so normalized-text matching alone
still appended semantic duplicates (e.g. the mtime-poll fix next to its
own curated write-up). Curated entries now claim covered commits with
backtick hashes (`aaa1111`, abbreviated or full); the generator skips
claimed commits. dedupeKey also strips GitHub's '(#N)' squash suffix.
The current [Unreleased] entries are annotated per the new convention.
@bytesnail
bytesnail merged commit 401086d into main Oct 5, 2026
15 checks passed
@bytesnail
bytesnail deleted the feat/changelog-dedupe branch October 5, 2026 04:18
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.

1 participant