## TL;DR
Fix the tag range: generate from the previous release tag (exclusive) to the new tag (inclusive). Duplicates mean the range started one tag too early.

## Error
```text
(release notes for v2.1.0 list commits already released in v2.0.0; no error text)
```

## Steps
1. Identify the range the writer used: check the job logs or config for the from/to refs. Expected: the actual range, e.g. v1.9.0..v2.1.0 instead of v2.0.0..v2.1.0.
2. Correct it to start after the previous release: `git log v2.0.0..v2.1.0` lists exactly the new commits. Expected: the range covers only new work.
3. Watch for tag weirdness: lightweight vs annotated tags, and tags on the wrong branch, both shift ranges silently. Verify with `git tag --list` and `git log --oneline` on the range. Expected: the range contains exactly the intended commits.
4. Regenerate the notes from the corrected range. Expected: no duplicates.

## When to use
- Release notes repeat the previous release's commits
- A docs agent picks the range itself
- Tags were recreated or moved

## When not to use
- Commits are genuinely new but look similar (not duplicates)
- The notes miss commits (a range that starts too late)
- You intentionally include prior context (mark it as such)

## Tool compatibility
Git-based changelog tools (conventional-changelog, release-please, semantic-release) and custom writers.

### Variant phrasings
### duplicates after a hotfix tag
Hotfix tags between releases confuse range pickers. Anchor the range on the actual previous release tag.

### agent uses dates instead of tags
Date ranges overlap across releases. Switch to tag ranges.

## Why it happens
Range selection is usually "latest N tags" or a guessed previous tag. Any off-by-one in tag ordering pulls the previous release's commits into the new notes.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_dUmBuXDf-Cqe_yCd_L9_gA
